moria-5.6.debian.1/0000755000175000017500000000000012234455730012170 5ustar pjbpjbmoria-5.6.debian.1/ChangeLog.19890000644000175000017500000015447605613574240014375 0ustar pjbpjb:::::1987 Fixes::::: 87 fixes deleted, see the 4.85 or 4.87 sources :::::1988 Fixes::::: 88 fixes deleted, see the 4.88 sources :::::1989 Fixes::::: --------------------- 2/26 all files: merged the umoria and PC-Moria sources creature.c: get_moves(), 12 numbers were wrong for monster movement wizard.c: a few more int to bigint_t changes needed in wizard mode commands files.c: fix columns in monster dictionary so that everything lines up misc2.c, moria2.c: line up columns for print_new_spells() and examine_book() 8 files: replace == with = in comments and strings magic.c, misc1.c, misc2.c, moria2.c, signals.c: missing/misplaced breaks monsters.c: 2 grey snakes, renamed one to green misc1.c: compact_objects, stmt which decrements cur_dis in wrong place spells.c: disarm_all should not set traps to zero, should just clear trap bits moria2.c: in jamdoor() i_ptr->p1 should be t_ptr->p1 moria2.c: in place_trap(), covered pits should transform to open pits moria2.c: mon_take_hit(), int i should be bigint_t i io.c: more prompt will now accept space/escape/return/linefeed io.c: EOF code did not work on machine with unsigned characters ------------------------ 2/27 save.c: missing controlz calls on error returns creature.c: don't let non-moving creature move if glyph prevented it from attacking creature.c: give monsters a chance to recover from Bash, depends on square of monster level moria2.c: give monsters a chance to ignore bash, function of hitpoints and level spells.c: fixed restore_level, needed while loop moria2.c: monster_multiply(), i=18 statement in wrong place, would not always multiply monster when it should --------------------- 3/2 moria1.c: get_panel(), add one to y and x on lines 945/950, prevent scrolling while inside rooms --------------------- 3/9 wizard.c: tmp_val = -999; for gold changed to tmp_lval signals.c: added SIGXCPU to list of signals that cause panic save spells.c: call monster_name before mon_take_hit in fire_bolt() moria2.c: move_char (), stop before attacking a creature dungeon.c: added move_char (5) to see_infra and see_invis setting and clearing --------------------- 3/10 creature.c: added take_hit (0, ddesc) line to every monster spell, ensure that player leaves resting/find/search modes potions.c: remove chp += mhp code from gain const potion, now chp = mhp moria2.c: change monster_death(), summon_object 4d2 instead of 4d3 so that comments match code creature.c: make_move(), prevent monster from moving again after opening a door, also, make chance of opening locked door dependant on monster level monsters.c: giant red ant lion, not hurt by fire, move&attack normally --------------------- 5/5 generate.c: fixed error in generation of type 3 (subtype 3) rooms misc2.c, config.c: added alternate wizard code/definitions treasur1.c: restore mana potion made more valuable (35 -> 350) staff of speed value increased (800 -> 1000) ring of sustain charisma level changed (7 -> 44) ring of stupidity level decreased (20 -> 7) potion of gain strength value increased (200 -> 300) variable.c: halfling clan elder had 0% chance gave warrior higher base to hit chance than paladin store1.c: digging tools must be identified before price is adjusted misc1.c: do not adjust cost of digging tools based on value of p1 change all mods to fields toac/todam/tohit to be += or -= several items (mostly cursed items) needed %P1 added to name for digging tools, inc p1 instead of replacing it, so that tools will still have same minimum values as specified in treasur1.c monsters.c: Forest Wight should be able to open doors. Grey Wraith should not drain mana moria1.c: fix stealth so that it uses the value of p1 treasur2.c: change 'a's to '&'s for doors spells.c: word of destruction should not put wall over character Could not use wand of drain life at a distance moria2.c: when in find mode, attack if run into creature only if can't see it -------------------------5/7 moria1.c,moria2.c: remove heavy weapon message from test_hit and put it in py_attack instead spells.c: teleport_away now calls unlite_spot if necessary, fixes bug that I thought had been fixed 3/28/88 save.c: for MSDOS: when restore save file, must search object list for secret doors/traps, and convert the '#/.' char to wallsym/floorsym, when save file, must do the reverse translation spells.c: unlight_area() was really messed up, is much shorter now, will always print "darkness" message now if it should misc1.c: cleaned up prt_map(), probably much faster now moria1.c: cleaned up light_room(), draw_block(), sub2_move_light(), they are probably much faster now all: changed print(char *, int, int) to print(char, int, int) in io.c misc1.c: crown of the magi, now has RL instead of see invisible ---------------------- 5/8 all: checked uses of fm/pl/tl for consistency,eliminate extra parens/tests/etc death.c: changed call to exit(1) to exit_game instead, io.c, dungeon.c: new function move_cursor_relative to position cursor on map --------------------- 5/13 Moria.doc: added changes to bring it up-to-date, ran through Spell again --------------------- 5/18 spells.c: polymorph monster spell incorrect, missing an else flag = TRUE line moria2.c: fix setting of reset_flag in find mode in move_char() routine Moria.doc: created MacWrite version for Macintosh, plus some more editing corrections --------------------- 5/29 death.c, externs.h, files.c, io.c, misc2.c, moria2.c: eliminated the function pad, replaced most calls with printf %-30s formats death.c: rewrote fill_str and renamed it to center_string, previously was returning pointer to local variable death.c: eliminated dprint, replaced it with calls to put_buffer signals.c: suspend handler now saves/restore special local chars (^R, ^W, etc) generate.c: rewrote blank_cave, should be a bit faster now externs.h, io.c, misc1.c, variable.c: eliminate used_line array, no longer call erase_line in prt_map in misc1.c misc2.c, moria1.c, store2.c: make sure cursor is always in the right place after an inkey call create.c, misc2.c: rewrite put_character and associated routines, line up columns, eliminate strcat/strcpy calls files.c: rewrote file_character so that it matches put_character, etc. io.c: fixed put_buffer so that it won't print past right edge of screen files.c, misc1.c, moria1.c, ms_misc1.c: loc_symbol rewritten, now checks values of pl/tl/fm, did not correctly handle monsters which were visible, but were not in a lighted spot moria1.c, io.c: rest() only erases MSG_LINE now if original 'hit ... to quit' message displayed, new function in io.c erase_non_msg does this misc1.c: magic_treasure(), fixed helms which had wrong else level of cursed items, added cursed rings of searching, set p1 value for amulet of magi ---------------------- 5/30 treasure1.c, treasure2.c: three axes changed from type 21 to 22, this prevents the Priest shop from buying these weapons --------------------- 6/2 creature.c, moria1.c, moria2.c, spells.c, types.h: massive reorganization of the way that visible monsters are handled, now ml is set if and only if the creature is visible on screen creature.c, externs.h, moria2.c: procedure check_mon_lite removed, calls to it replaced by calls to update_mon () misc1.c: delete unused code creature.c, moria2.c: two places needed to test fm in addition to pl and tl spells.c: need to set fm/tl/pl before call to lite_spot/change_trap, eliminate some unncessary calls to lite_spot, eliminate unneccsary clearing of fm ------------------------- 6/8 dungeon.c, moria1.c, moria2.c: allow searching while blind, decrease chance of successs if blind or have no light moria1.c, moria2.c, store2.c: change prt("", x, y) to erase_line (x, y) misc2.c: replace all "\0" with just "" io.c, moria2.c, scrolls.c, store2.c: add '.' to end of sentences dungeon.c, misc2.c, moria2.c, scrolls.c, store2.c: add msg_flag = FALSE after lots of msg_prints, to make sure never get " -more" message line creature.c, dungeon.c, spells.c, staff.c: don't print 'light' message if blind moria2.c: disarm_trap(), make no_light and blind same penalty, increase blind/no_light and confused penalties moria1.c: rewrote area_affect, delete redundant code, don't stop at doorway if no_light and it is unlit generate.c: fixed error in build_tunnel, stack points could overrun stack ------------------------ 6/9 moria1.c: change test_hit so that always miss 1/20, and always hit 1/20 moria1.c, moria2.c, spells.c: changed fval incorrectly when manipulating doors, only change to corr_floor2 if next_to4 a room space creature.c: in get_moves, change 1.732 to 2, makes it faster, also can no longer circle monsters by moving in a diamond shape death.c, io.c, files.c, main.c: for MSDOS, don't leave the highscore_fd file open permanently save.c: save value of total_winner, in case of a forced call to save_char() all, types.h: deleted MSDOS ifdefs, the bytlint/byteint/wordint/worlint type definitions were confusing, so changed all to int8/int8u/int16u/int16 generate.c: rewrote loops to try to speed up level generation ---------------- 6/12 misc1.c: for items with duplicates in treasure1.c, set level of all equal to that of lowest treasur2.c: several items did not match same item in treasure1.c ----------------- 6/13 treasur2.c: wands/staffs in store now have same level as those in dungeon dungeon.c, misc2.c, moria1.c, ms_misc.c, store2.c: removed some ASCII dependencies ------------------ 6/16 externs.h, constants.c, generate.c, misc1.c: fixes to make level generation faster, rearrange order build_tunnel makes comparisons, call correct_dir directly instead of through rand_dir, rewrite loops, rewrite next_to4, rewrite next_to8 externs.h, files.c, misc1.c, moria1.c, ms_misc.c: loc_symbol returns char == the following are due to CJS (Bruce Moria) create.c: in get_money(), charisma was subtracted and added, now only add desc.c: unquote() did not work at all, rewrote the whole thing in identify, string[0] == 'T' should be string[1] moria1.c: area_affect, for direction 1, the 3 should be a 2 misc2.c, moria2.c, scrolls.c, spells.c, store2.c: change msg_print(" ") to "" store2.c: eliminate erase_line/display_commands at end of purchase_haggle config.h: for defined(Pyramid), define ultrix eat.c: py.stats.intel to s_ptr->intel creature.c: in make_move(), set m_ptr at begining of function, in mon_move(), set m_ptr at begining of function, test cmove before calling randint in mon_move() change if (randint(10) > py.misc.stl) to && (randint(...)) dungeon.c: move random teleport outside innermost loop, put with other checks == end CJS fixes == creature.c: collapse a large number of if (...) if (...) constructions to if (... && ...) constant.h, desc.c, externs.h, generate.c, misc1.c, rnd.c, save.c,variables.c: all versions now use rnd(), rnd does not use SYSV calling conventions anymore BSD random() states eliminated generate.c: added code to build_tunnel to prevent infinite loops --------------- 6/19 *.c: collapse a large number of if (...) if (...) constructions to if (... && ...), delete unneeded braces ---------------- 6/21 creature.c, spells.c: build_wall and earthquake, now kill monster if it can not move through walls, and it can not move out of the way of the new wall, also, does more damage to those that escape, in creature.c, if in wall, must escape to empty space ----------------- 7/17 main.c: added a setbuf call, for buffered output ------------------ 8/4 merging changes due to Christopher J Stuart...zillions of changes stat structure changed externs.h: move functions definitions for lint to here create.c: help functions sorta' added, money now more dependent on stats, really good/bad characters eliminated, etc... ------------------ 8/8 creature.c: new function disturb used, stop attacks if player dead, add message for two attacks which had no message, confuse-monster only works if monster actually hits, door bashing different and noisy too!, creatures only eat lower level creatures, monster drawing changed, monster memory added, etc... ------------------ 8/9 desc.c: eliminate lots of unnecessary strcpy/strlen/etc calls, can inscribe objects, store/dungeon objects will be merged in the inventory when objects are identified, if curse a special object it loses its special ability, %d code for damage, %a code for armor, etc... eat.c: misc changes... ----------------- 8/11 help.c: moved help text into files, added monster recall info, etc... ----------------- 8/14 Moria.doc: editing changes, removed lots of unnecessary hyphens io.c: rebuilt it (accidentally deleted current version) death.c: scoring procedures moved elsewhere, print_tomb more efficient and uses far less stack, final char display different, upon_death changed to exit_game, etc... generate.c: added STATIC and void magic.c: reduce indentation, increase spell damage, 7 dam/mana for Magic Missle, 4 d/m for balls, 5 d/m for bolts, etc... misc1.c: crowns higher chance of magic, monster dist changed to increase chance of higher level monsters, unnecessary uid/eid calls deleted, m_level changed to include level[0] monsters, highlighting for ores, disappear percentages for objects in compact_obj() modified, '!' char added to magic descriptions, damage added to bows ------------------- 8/15 misc2.c: print message if gold/object created under player, stat handling completely changed, new func title_strings, search/rest/paralysis/count message print changed, new func prt_speed(), new stat functions, can hide stat changes if unknown, get_name uses loginname if none entered, change_name can print to file, inven drop/carry/etc changed to be a little simpler, new func join_names, spell_chance/learn_spell/etc chnaged to be a little simpler, get_spell with capital letter verifies choice, etc... ---------------------- 8/16 monsters.c: no change treasure1.c: %d added to weapons, %a added to armor, plus to dam added to bows, mage's guide should be mages' guide?? appostrophe removed ---------------------- 8/17 treasure2.c: change & in traps to a/an, scroll/potion subvals changed to 200 plus value in treasure1.c, etc... potions.c: every potion prints message, ident true only if something noticable happens, greatly reduce indentation, stat handling different, etc... prayer.c: reduce indentation greatly, use up mana if prayer fails, etc... scrolls.c: reduce indentation, only ident if something noticable happens, for identify must search for new location of scroll, etc... sets.c: ifdef out unused functions dungeon.c: add command counts, use new func disturb(), double regen if searching, damage if really hungry, messages for protevil resist_heat and resist_cold, new code for quiting rest mode, move teleport code outside inner loop, add code to check strength/weight, find mode done differently now, allow ^char for control characters, all command chars translated to rogue_like chars, new commands = (options) { (inscribe) V (view scores) M deleted but W improved : (map area) rogue-like summon ^S -> &, etc... ---------------------- 8/24 files.c: init_scorefile deleted, intro->read_times, don't modify argv, new func helpfile, print_map deleted, print_monsters deleted, file_character now takes filename as argument, etc... io.c: lint defs, new suspend function, much better curses handling, new func moriaterm and restore_term, inkey does refresh on ^R, flush should work now, new funct get_check, save_screen, restore_screen, etc... constant.h: add defs for STATIC, ESCAPE, stats, increase treasure in streamers, change store min and turnaround amount, MAX_MON_NATTACK, MAX_EXP wands.c: inscribe wand if empty, reduce indentation, etc... staffs.c: inscribe staff if empty, reduce indentation, etc... spells.c: identify- update stats if affected, allow ident of equip items; better light_line messages; when set pl false, must set fm false also; misc, etc... ------------------- 8/29 moria1.c: new function enchanted(), part of py_bonuses split into calc_bonuses, cur_char1/2 deleted, complete rewrite of inven_command routines, new functions check_weight/verify, can display weights, get_item can show either inven or equip, options added, run code completely rewritten, misc, etc... --------------- 8/30 store1.c: item_value has *item->number removed, many routines changed to pass item pointer, identify removed from store_carry, known1/2 put in store_create, store_maint alg changed, etc... store2.c: clean up handling of msg_flag, incremental haggling in get_haggle(), display_command moved from purchase/sell_haggle to store_purchase/sell, enter_store code cleaned up, etc... config.h: misc... externs.h: add new variables, delete old variables, rearrange stuff, etc... types.h: added logging structure and recall structure, etc... variables.c: add new variables, delete old variables, rearrange stuff, remove learn from spell structure, change titles so none shared between classes, etc... -------------- 8/31 moria2.c: weight bug fixed, py_attack did not decrement inven_weight when inven_wield was a missile, and the player was carrying more than one of them -------------- 9/1 moria2.c: carry has pickup option, new functions for inscribing objects, summon_objects returns type/number of objects created, ditto monster death, new function check_view, add todam for using bow/arrow, bashing changes, new sub py_bash extracted from old bash code, jamdoor p1 values changed successive spikes have smaller effect, etc... ------------- 9/2 main.c: add bruce moria comment, new options, read environment variables, etc. wizard.c: wizard can change weight and speed of character, etc... unix.c: new file, contains UNIX specific code for user_name, check_input, and system() signals.c: completely rewritten to be much nicer, same functionality recall.c: new file, for printing out monster memory info save.c: completely rewritten, same functionality, I think ------------- 9/7 lint on mips machine ------------- 9/8 lint on AIX (SYS V) ------------- 9/9 lint on ultrix ------------- 9/11 fix anonymous errors in order to get the program to compile... io.c, ms_misc.c: put screen_map in io.c, and made it a default feature signals.c, main.c, io.c: on EOF, the program now returns ESCAPE char until exits dungeon(), then saves with no penalty ------------ 9/12 externs.h, desc.c, variables.c, types.h: mushrooms/colors/rocks/etc changed to char pointers instead of char arrays, saves space, make random init faster, change player title to char pointers also moria1.c, potions.c, misc2.c, eat.c, dungeon.c, creature.c: cleanup handling of chp and cmana, call prt_c* only once every time they change dungeon.c: set pointers only once at start of procedure eat.c: reduce indentation io.c, dungeon.c: remove msg_flag = FALSE line from inkey and put it in dungeon.c where get command ------------ 9/14 creature.c: change put_qio calls to just setting screen_change to true dungeon.c: remove superfluous erase_line and put_qio calls many: make character numbers more clear, 'a' for 97, DELETE for 127, etc... desc.c: objdes() bug with ins_buf handling, now clear ins_buf if none many, moria1.c: made "Which dir?" default for get_dir() -------------- 9/15 misc1.c, monsters.c, treasur[12].c, many others: changed all hit ponts from strings to a char array of size two, changed damroll to take two characters instead of a string, this eliminates most all scanf calls -------------- 9/18 monsters.c, creature.c, types.h: replaced strings containing monster attacks with 4 byte array containing index into a monster attack table, this eliminates the rest of the scanf calls, and saves space creature.c: many duplicate damroll calls in make_attack collapsed into a single damroll call moria2.c: in chest_trap(), moved exploding chest trap to end to avoid dangling pointer problem; in twall, only light spot if c_ptr->tl is true; wizard.c, recall.c, desc.c, files.c: changes to fix handling of new damage types for monsters and weapons ---------------- 9/19 many files: eliminated redundant trap_lista, fixed place_trap so that it no longer takes a typ parameter, change_type no longer calls place_trap, negative level values for traps all made positive and diasrm_object() changed appropriately externs.h, dungeon.c, misc2.c, moria1.c, variables.c: eliminated print_stat variable since it was not used very much ---------------- 9/21 create.c, externs.h, variable.c: eliminated bit_array variable variable.c: eliminated names of unused Rogue class spells many files...: changed the floor/wall definitions from variables to constants, changed the values to make tests easier, all fval comparisons now use manifest constants, door type floors eliminated since new find/run code made them unnecessary constant.h, misc2.c, externs.h, variable.c: changed var stat_column to constant, eliminated password variables many files: changed moria_flag to new_level_flag, and reset_flag to free_turn_flag ------------- 9/23 merged Xenix diffs and Atari ST diffs treasure1.c: potion of sleep no longer cures blindness wands.c: wand of wonder was wrong had 2 << randint() instead of 1 << randint() eat.c, potions.c, scrolls.c, staffs.c, treasur2.c, wands.c: added store bought flag 0x80000000 to all food/potion/scroll/staff/wand objects in treasure2.c, modifed the code so that these objects do not give experience when used all files: removed all floating point code except for randnor() and los() many files: hp_player(-damage,"") calls did not work, change them all to direct calls to take_hit(damage), hp_player string parameter removed since no longer used ------------- 9/25 constant.h, config.h, externs.h, variable.c, misc1.c, misc2.c, potions.c: floating point randnor code replaced by integer on that uses a table, definition of MAXINT removed so there are now no differences between 16 bit and 32 bit versions of moria, MAXSHORT and MAXLONG defined Makefile, misc1.c, externs.h: calls to floor removed, math library no longer used!!, DONT_DEFINE_CLASS def for SUN4 no longer needed ------------- 9/27 misc1.c: replaced los code with an integer arithmetic version by jnh (Joseph Hall), moria now uses no floating point numbers dungeon.c, files.c, moria1.c, store2.c, wizard.c: removed all sscanf calls except for those in ms_misc.c, and one "%lx" in wizard.c ------------ 9/28 treasure1.c, treasure2.c, types.h: change subval and number to 8 bit integers, move flags after name, move number before weight, save 12 bytes per constants.h, etc: INVEN_MAX definition removed, INVEN_ARRAY_SIZE 1 smaller variable.c: store_choice now array of 8 bit integers monsters.c, treasure2.c: change t_level and m_level to array of 16 bit ints many: interpretation of subval changed to fit it into byte, new range uses p1 to decide whether stacking permitted, torches can now stack create.c, types.h: changed size of history from 400 to 240 characters, also print as lines of 60 instead of lines of 70 variable.c, misc2.c, types.h: changed definition of spell_type from 12 to 6 bytes, new array spell_names to prevent duplicate strings, no longer have entry for warriors variable.c, types.h: human female too light, made 150 from 120, also changed every base/mod field from 16 bits to 8 bits types.h, variable.c: in background_type, change next and bonus fields to 8 bit integers, added 50 to bonus to make it positive ----------------- 9/29 monsters.c: massive changes to monster file to fix inconsistencies ----------------- 9/30 set.c: make flasks of oil vulnerable to frost and fire, like potions moria2.c: if set off a trap, temp set confused to zero to ensure that player will move onto the trap instead of in random direction io.c, externs.h: confirm() no longer used, deleted treasur1.c, treasur2.c: give non overlapping subvals to potions/scrolls, duplicate ones caused problems for giving random names desc.c, treasur1.c: %M for mushrooms changed to %m recall.c: fix printing of monster hit points, two numbers instead of a string moria2.c: new look code from bruce moria, look in arcs so that can see anything on the screen, allows access to monster memories generate.c, misc2.c, moria1.c, moria2.c: various fixes to reduce code size, increase speed, etc... misc1.c, etc...: popm and popt no longer take a pointer, instead return int, pusht takes an int8u now instead of an int as a parameter ---------------- 10/1 all: added copyright notice to every *.[ch] file --------------- 10/3 config.h, creature.c, recall.c, save.c: fixed a few bugs picked up by the ultrix compiler dungeon.c: disabled the save command -------------- 10/6 create.c, files.c, dungeon.c, main.c, save.c: wrote helpfile function, changed calling sequence so that caller does not have to do anything constant.h, desc.c, variables.c: eliminated lots of excess colors/rocks/etc. eliminated all duplicates except between potions and mushrooms types.h: fixed _frac problem with exp and chp, had to be unsigned shorts misc1.c: made traps invisible again moria1.c, moria2.c, store2.c: replaced strcpy(string, "constant") code with p = "constant" where possible treasure1.c, treasure2.c: changed subvals for wands/staffs/amulets so that they start at zero, and don't have any missing numbers spells.c: teleport_away() must clear m_ptr->ml before calling update_mon() moria1.c, spells.c: check lite_spot() calls, eliminate unnecessary ones death.c, misc2.c, wizard.c: eliminated lots of unnecessary blanks in string constants --------------- 10/7 misc1.c, moria2.c, treasure1.c, treasure2.c: fixed lamp/torch subvals, again can not let torches have subval >= 64, the torch wield code will not work store1.c: don't let items with subval >= 192 stack in stores, they are always handled as a group anyways spells.c: fire_bolt and fire_ball fixed in regards creature lighting variable.c: store_choice for temple wrong because broad aze renumbered earlier, changed 13-15 to 12-14 constant.h, dungeon.c, moria1.c: added print ac flag to status field, calc_bonus sets flag, prevent printing AC while in store create.c: dis_ac must have dis_tac added to it spells.c: detect_monster evil and insivible now set m_ptr->ml when print monster on screen, then creature() will correctly erase them --------------------- 10/8 types.h: fixed _frac problem with cmana, had to be unsigned short moria1.c: in inven_command wear code, print 'too heavy' message after print wielding message store1.c: item_value, must multiply value by item->number before returning store1.c: sell_price return zero if item should not be put into store monsters.c: disenchanter bat sleep set from 0 to 1 all: eliminated all unnecessary elipses constants.h, creature.c, dungeon.c, eat.c: new defines for the creature move, spell, and defense fields, eliminated all hex constants from the 3 c files ------------ 10/9 moria2.c: fixed falling rock trap in move_char(), step back so that player is not under the rubble variable.c: put copyright message in string, so that it appears in executable spells.c: create_trap modified to light up trap, in case it is an open pit all:replace prt calls with put_buffer where ever possible, because it's faster externs.h, io.c, signals.c: put ignore/default/restore_signal code back in wizard.c: rewrote the version info dungeon.c, moria2.c, signals.c: modified to use get_check() for consistency ------------ 10/10 several spelling errors in CJS code misc1.c: forgot to change magic_treasure code when changed subvals a couple of days ago for wands/staffs/amulets/rings externs.h, files.c, misc2.c, types.h: wrote new stat code, all stat bugs fixed now, 6 stat values now, get_dis_stat() eliminated, new function modify_stat(), misc2.c: get_obj_num changed, to increase probability of getting higher level objects misc1.c, treasur1.c: had to change gain stat bits, the low 6 order bits of treasure flags, because changed the order earlier ---------------- 10/11 all: changed all 4 or less case switch statements except for one large one in generate.c to nested if statements, this is smaller and faster ---------------- 10/12 dungeon.c, generate.c, moria1.c: new_spot moved from dungeon to generate because alloc_mon and place_win_mon use character position, fixed minor new_spot bug constants.c, misc2.c, dungeon.c: bst_stat() can not call prt_stat, changed to set py.flags.status, new stat change flags defined, and stat print code added to dungeon.c creature.c: many duplicate disturb/strcat/msg_print brought outside the switch statement in mon_cast_spell all: changed all unlite_spot() calls to lite_spot() calls, changed 'if (test_light()) lite_spot()' code to just call lite_spot, this fixes many subtle bugs, mostly dealing with mon vis to infravision, unlite_spot code deleted files.c, misc2.c: added stat_adj(A_INT) to srh which was wrong misc2.c, spells.c, moria1.c, types.h: id_stat() and hid_stat[] eliminated no more hidden stat values, display arg dropped from bst_stat() files.c, misc2.c: hex values replaced with constants ----------------- 10/14 constants.h, store1.c: increased store turn around from 4 (avg 2.5) to 9 (avg 5), changed store_main() to always call store create/destroy regardless of bounds, lowered values of bounds MIN and MAX --------------- 10/18 moria2.c: when open chest, clear TR_CURSED flag, which just also happens to be monster win flag, to prevent easy wins constants.h, misc1.c->wizard.c: replaced remaining hex magic numbers with manifest constants dungeon.c: added code that gives a player a chance of noticing that items in inventory/equipment list are magical, the chance is much higher for warriors than for magi --------------- 10/19 dungeon.c: ^P^P did not clear the line with the pause_line message misc2.c: prt_state() did not clear all 3 digits of repeat counts all: moved lots of procedures around to increase number of static fuctions, also made sure every C file less than 60K create.c, extern.h, misc2.c, spells.c, variables.c: change way that mhp are calculated, new function calc_hitpoints(), new array player_hp[] which contains player mhp for each level extern.h, main.c, misc2.c, potions.c, spells.c: change way that cmana are calculated, new function calc_mana(), called whenever gain level, lose level, or learn/forget spells extern.h, main.c, misc2.c, spells.c: change the way that spells are learned and lost, learn_spell/learn_prayer deleted, new function calc_spells, new spell type state forgotten, new var spell_forgotten, etc. -------------------- 10/20 monsters.c: made spirit troll into 'G', made invisible, pickup, carrys obj, added drain wisdom attack, added drain intelligence attack to green glutton ghost all: moved all msg_print(NULL) calls into io.c, specifically, clear_screen(), erase_line() and prt() moria2.c, spells.c: two places that called test_light to see if monster or moving object lit were wrong, changed to eliminate check of fm creature.c: update_mon() failed when hallucinating, changed print(cchar,...) to lite_spot() call variables.c: adjusted call stat adjustments, mainly to make priest harder, gave priest negative str adjust, inc expfact from 10% to 20% misc2.c: new funcs prt_int() and prt_long(), same as prt_num/prt_lnum() except no string argument, ": " moved into prt_num/prt_lnum string spells.c: all wands now have limits on range monsters.c: doubled Balrog eye sight from 20->40, evil iggy from 20->30 eat.c: increase hp gain for 22/23/24, increase hp loss for 27 constant.c, eat.c, potions.c, scrolls.c, staffs.c, treasur2.c wands.c: eliminate store bought flag, only gain exp when use an item if the use identifies the item ----------------- 10/23 magic.c, wands.c: spell/wand damage did not match creature.c: monster stuck door bashing got sign of i_ptr->p1 wrong recall.c: change corrosive gases to poison gases externs.h, moria1.c: draw_block(), minmax(), maxmin() deleted, minmax and maxmin calls were unnecessary, draw_block only called from one place, sub2_move_light combined with sub1_move_light, sub4_move_light combined with sub3_move_light, creature.c: fix mon_move() so that creatures that never move increment their r_attack[0] when standing next to the player, for Quylthulgs spells.c: detect object and detect treasure set tl, which could also light up monsters, they now set fm ----------------- 10/24 spells.c: can not gain exp by disarming traps created by a scroll types.h, magic.c, prayer.c, variable.c, misc2.c, constant.h: removed sname from spell_type since it was a trivial value, changed sexp from 16 bits to 8 by dividing value by 4, saves about 310 bytes many files: eliminated long stretches of blanks in strings, remove repeated chars from strings, typically " : ", saves over 1K of data size --------------- 10/25 spells.c: aiming a ball type wand/spell at a 1-thick wall resulted in damage to creatures on the other side of the wall, now it doesn't misc2.c: inc_stat changed so that player gains 1/6 to 1/3 of the distance from the max 18/100 stat, 0 to 100 takes 13 gain stat potions, dec_stat changed so that player loses 1/4 to 1/2 of the distance from the max 18/100 stat, 100 to 0 takes 13 lose stat potions misc2.c: print_spells() modified so that spell are always listed with the same letter, i.e. the letter does not depend on whether or not you know the spells that precede it --------------- 10/26 death.c: day string was size 11 should be 12 dungeon.c: make 'magik' detect same chance for each class, need to set i_ptr = &inventory[INVEN_LIGHT] before testing player_light, this could cause the light to go off permanently misc2.c: calc_mana and calc_spells use p_prt->lev - class[].first_spell_lev-1 instead of just the player lev types.h, variable.c: add new field to class info, first level in which the player can learn a spell, used immediately above variable.c: green glutton ghost no longer drains int misc2.c: print 'welcome to level message' before learning spells --------------- 10/28 config.h, externs.h, dungeon.c, wizard.c: version info put in a help file, game_version() function deleted files.c: removed obsolete print_map() and print_monster() code treasur1.c: made ring of WOE decrease wisdom, to balance ring of stupidity, removed trailing ^ secret symbols which made no sense, changed constant values from known2 to known1, such as ring of lordly protect armor class values store1.c, store2.c, externs.h, types.h: add storenice feature by Dan Berstein, if (good bargain > 3 * bad bagains + 20) then always get final price in that store, two new functions, noneedtobargain() and updatebargain() moria1.c: fixed wear command so that it prints inven letter of item removed, and equip letter of item worn, added extra param to remove() generate.c, moria1.c, moria2.c, types.h: added an 'lr' flag to cave_type, this is set for every space in or next to a room, lr is true for lit rooms, and false for dark rooms, find_light() function deleted as it was no longer necessary, twall lights spots that have lr set moria1.c, moria2.c: decrease search chances if hallucinating, decrease disarm chances if hallucinating, look fails completely eat.c: print message "You feel drugged." for mushroom of hallucination moria1.c: eliminate unnecessary in_bounds() calls io.c: check to make sure tabs are all 8 character apart treasur2.c: made object_ident array bss misc2.c, moria1.c: fix calc_bonuses() so that it when wielding heavy bonuses, it subtracts the weight penalty from dis_th (display to hit), check_strength() modified to call calc_bonuses() misc1.c: fixed compact_objects() and compact_monster() so that they update screen when deleting objects/monsters creature.c, spells.c: put message in aggravate_monster(), took out redundant mesasge in creature.c moria2.c: modify py_attack(), inven_throw() and py_bash() to make it more difficult to hit monsters which are not lit ---------------- 10/31 moria1.c: sub3_move_light() modified so that it does not print @ when in find mode recall.c: had an 'i == 11 | i == 18' which should have been a || printed out 11st,12nd,13rd levels incorrectly, now uses 'th' moria1.c: fix see_wall, it assumed walls are # which is not true for PC/Atari spells.c: breath() could do damage on the other side of walls, added an los() call to prevent this moria1.c: area_affect treated 'potential corner' and 'branching side corridor' identically, which is wrong, added see_nothing() so that these could be handled separately ---------------------- 11/1 moria1.c: when wearing object and must remove current object, fix code to use inven_check_num to see it is possible; in wear code, when remove old object check to see if inven_ctr increases before actually increasing wear_high constants.h, misc2.c, moria1.c, store1.c, store2.c, treasure1.c, treasure2.c: change definition of subval 192 so it can be used for torches, it only stacks with others if have same p1 value, but it is always treated as a single object, change ITEM_* definitions in constant.h to match new definition, fix all code fragments that test subvals desc.c: change to use new ITEM_ definition moria1.c: fixed the potential corner/corridor intersection bug in the find code again, except this time it works better than the original code ------------------------------ 11/3 variables.c: decrease priestly HP bonus from 3 to 2 moria1.c: fixed wear code bug, called inven_check_num() with item not slot ----------------- 11/4 moria2.c: in tunnel(), print message if player tries to dig with hands moria2.c: several places where object/treasure picked up did not clear c_ptr->fm, this is necessary since it might be set by detect spell --------------- 11/7 moria1.c: fixed find_init so that moves straight into a corner would correctly run around the corner moria1.c: changed the examine potential corner code in area_affect(), it would run into rooms if corridor entrance next to a wall, at least it doesn't do that for lighted rooms anymore ----------------- 11/8 prayer.c: in remove curse spell, only clear flag for items that are wielded or worn io.c: truncate strings at col 79 instead of 80 if BUGGY_CURSES defined moria1.c: print weights in show_inven and show_equip at col 71 not 72 io.c, misc1.c, moria1.c: change highlight mode for walls to display '%' instead, this is much more portable that original code that used standout mode and the high character bit, changed print(),loc_symbol(), and see_wall() help.c: change help documentation for % character wizard.c: modify wizard_create and change_character functions, add whitespace, exit if get_string fails (i.e. typing ESCAPE exits), modify get_string limits to more reasonable values, remove switch for setting tchar moria_wiz_help, moria_owiz_help: correct errors in command list death.c: add msg_print(NULL) after show_inven() in print_tomb() so that inventory can't accidentally scroll of screen before exiting creature.c, moria2.c, spells.c: can't call prt_experience() in mon_take_hit() as this gives "new level" message before "killed monster", move prt_exp calls to after msg_print at everyplace that calls mon_take_hit() dungeon.c: modified repeat count code so that can edit the number entered leave cursor on msg line while entering repeat count moria2.c: change summon_object() so that it will only create objects within los of point where monster dies --------------- 11/9 store1.c: stacking code in store_check_num() and store_carry() did not handle torches correctly, changed to be the same as inven_check_num code in moria2.c wizard.c: fixed mistake in change_character(), put *tmp_str != '\0' test in inside if statement, not outside one externs.h, misc2.c, moria2.c: fix printing of spell characters from get_spell, print_spells changed consec TRUE to nonconsec == -1 for consecutive case, otherwise spells start with nonconsec=='a', added new arg to get_spells() first_spell which becomes nonconsec when call print_spell wizard.c: move 'gold' from end of change_character to right after 'mana' since it is more frequently used than the rest misc2.c: alloc_object(), fix it so that objects are not created underneath the player, this was a problem for rubble and traps misc1.c: allow sling ammo to be enchanted in magic_treasure() store1.c: fix search_list() call for ammo in item_value(), was passing 1 ?!? instead of correct subval treasur2.c: subval for spike wrong, change from 192 to 193 misc1.c: remove see invisible from slay monster arrows, since it doesn't make sense variable.c: change blows_table entry for STR/W .5-.7 and DEX 10-18 from one to two, the value of one made things too difficult for low level mages monsters.c: for all monsters which used to be sleep value of 1 (old style), change their new style sleep values from 0 to 1 recall.c: stupid typo, change CM_CARRY_OBJ|CM_CARRY_OBJ to ..OBJ|CM_CARRY_GOLD ---------------- 11/10 moria2.c: disarm() had signs switched for trap chances, "tot - 100 + level" changed to "tot + 100 - level" variable.c: change "tin plated" to "tin-plated" and etc. ----------------- 11/13 save.c: changes to get the save code working again moria2.c: when move onto a trap, instead of restoring confused count, should increment it by the old value, since the trap may have set it generate.c: for type 2 rooms, make them dark below level 25, not 30 moria2.c: when close a door, print "Something" instead of monster name if the monster blocking the door is invisible moria2.c: in tunnel(), make the digging chance for non digging weapons equal to their max damage + tohit bonus instead of proportional to weight, the old code made lances better for digging than shovels moria2.c: change py_bash() chance, make it a function of monster hp + monsters average max hp instead of level --------------- 11/15 save.c, undef.c: restore_stats function eliminated, replaced by call to read py.stats from file, other fixes to get restore code working creature.c: if creature never moves, kill it if it happens to be in a wall instead of moving it out of the wall generate.c: everywhere that TMP1_WALL is used, must also set fopen FALSE so that place_object(), vault_monster() etc will work correctly prayer.c: removed cure_blindness() and cure_confusion() from Holy Word spell, since could not pray while blind/confused signals.c, io.c, externs.h: eliminate redundant definition of signal() in signals.c, also eliminate suspend_handler and assignment to it from signal(), make suspend() non-static moria2.c: in look(), put blind and image tests before get_alldir() moria2.c: in look() change [y to recall] to [(r)ecall] creature.c, externs.h, generate.c, misc1.c, monsters.c, moria1.c, moria2.c, save.c, spells.c, types.h, constant.h: change m_list from linked list to a linear list, muptr deleted, monster_type nptr field deleted, function pushm deleted, now all scans of m_list go from mfptr (which always points at last element) to MON_MINIX == 2 misc1.c: compact_monster no longer calls prt_map(), which is unnecessary --------------- 11/16 eat.c: fixed restore charisma mushroom, print 'stops' instead of 'starts' moria2.c: fix calculation of avg_max_hp in py_bash(), didn't check CD_MAX_HP monsters.c: spirit troll too hard to hit when can't be seen, lower AC 56->40 treasure2.c: fixed scare_monster trap, the subtype value was wrong 63->99, and the level needed 100 added to it misc2.: fix get_spells(), must add first_spell to *sn instead of subtracting from spell[i] creature.c: in mon_move, return immediately if creature is killed because it is in rock ---------- 11/17 externs.h, spells.c, scrolls.c, prayer.c, staffs.c: change dispell_creature() to dispel_creature() spells.c: dispel_creature uses m_ptr->ml after calling mon_take_hit() which is wrong, now save value before calling mon_take_hit() moria2.c: turn find_flag into a counter, when it reaches 100, exit find mode with message "You stop running to catch your breath.", prevents infinite loop generate.c: fixes to help prevent isolated rooms, in build_tunnel() make sure tunnel has gone at least 10 spaces from start before stop it, in cave_gen(), copy [yx]loc[0] to [yx]loc[k] so that can build tunnel from last room to first spells.c: light_line() called lower_monster_name() which is wrong, change to monster_name() call externs.h, creature.c, moria2.c, spells.c: removed seen argument from mon_take_hit, as it was used inconsistently, only get credit for a kill if monster is visible when killed save.c, dungeon.c: call disturb in save_char() to turn off searching and resting, remove search_off call in dungeon.c as is no longer needed variable.c: remove initialized data for py and old_msg since were (mostly) zero, set f_ptr->food and f_ptr->food_digested in main.c constant.h: delete some unused constants, rearrange the order of a few others ------------ 11/18 variables.c, externs.h, monsters.c, treasure2.c, save.c: every variable written to save file needs definate size, can not be just 'int', also spell_forgotten now read/written -------------- 11/20 spells.c: sleep_monsters1() did not set NO_SLEEP info for monster memory externs.h, moria1.c: changed new_spot to accept short pointers since char_row and char_col are now shorts creatures.c, spells.c: multiply_monster(), removed slp parameter since it was always FALSE, added monptr, to fix the m_list bug creatures.c: new m_list code fails when call delete monster from within creatures(), fixed it by changing some calls to delete_monster() to call delete_monster() only if the dead monster is between the current monster and mfptr, otherwise, call fix1_delete_monster() externs.h, creatures.c, spells.c: breath() has new argument monptr, to fix the m_list bug externs.h, creatures.c, spells.c: two new functions, fix1_delete_monster() and fix2_delete_monster() which together equal delete_monster, these are called from within creatures() when a monster is killed many: eliminate the fopen field since I had 5 bitfields in the cave structure, and it is much easier to only save 4, added a BLOCKED_CORR case for secret/closed/locked/stuck doors and rubble, all code that used to test fopen now tests fval, most code that used to set fopen is now gone since it was redundant with fval setting code moria2.c: fixed disarm() so that if there is a valid trap to disarm, it will print "Something/monster_name is in the way!" just like close door." generate.c: place_stairs() could place them on the boundary, make sure that x/y can never be 0 or cur_xx-1, also, in town_gen(), call place_ boundary() before place_stairs(), looks better, though not necessary moria2.c: fixed openobject() so that if there is something to open, it will print an message just like closeobject if there is a monster in the way save.c: fix another save file problem, noscorefile defined as int in get_char, just eliminated it and use noscore instead --------------------------- 11/22 moria2.c: fix1_delete_monster() has to set m_ptr->hp to -1 creature.c: monster eating code checked monster exp wrong, was using cptr to index into the c_list creature.c: in creatures(), call fix2_delete_monster if hp < 0 moria2.c, spells.c: dragon breath, wand bolts, wand balls, and thrown objects were visible even when blind, added checks, only print them if can see moria2.c: tunnel(), print message "* is in the way" if there is a monster in the spot where the player is trying to tunnel -------------- 11/23 save.c: player_hp was not saved/restored, total_winner and panic_save were not restored ------------- 11/27 moria2.c: in tunnel, add the weapon damage to its digging ability create.c: get_history(), clear the history strings before writing them with new values, to get rid of old strings variable.c: for background strings, change "1st child" to "first child" store2.c: add parameter to get_haggle() last_offer, in sell_haggle and purchase_haggle must set new_offer to 0, in get_haggle only allow incremental bid if new_offer == last_offer, i.e. at least one previous bid has been made dungeon.c: in main loop, call creatures(FALSE) to light/unlight creatures when ever player_light value changes ---------- 11/28 save.c: new save code, to reduce size of save file, and to make the savefiles portable constant.h, desc.c, generate.c, misc1.c, misc2.c, moria2.c, save.c: changed the t_list from a linked list into a linear array of entries, just like the previous m_list change, new constant MIN_TRIX, all pusht calls changed to delete_object where ever appropriate, etc. ---------- 11/29 misc1.c: increase p1 value for crowns of seeing by multiplying by 5 ----------- 12/4 creatures.c: change stealth code, instead of randint(10) < stl, it now cubes randint(64) and compares against 1 << (17 - stl), the result is that a change of one in stl always decreases monster notice chance by 80%, and perfect stealth is impossible wizard.c: allow wizard to enter any stealth between -1 and 17 save.c: extensive changes to save code competed, save files are now xor encrypted, and are supposedly portable, all savefile protection code is gone ---------- 12/5 save.c, undef.c, misc1.c: fix a few lint errors changed version number to 5.0.8 and release the sources creature.c: changed stealth code, amount monster woken by from 100 to 125 (used to be 75 before 12/4) -------- 12/6 spells.c, creature.c: changed the way wall building wands work again, kill creature if it never moves, otherwise do a little damage, if creature can not move out of rock in mon_move, then do more damage and remove the wall ontop of the creature various: check use of "?", especially in get_check() and verify() prompts, verify changed to replace the period with a question mark spells.c, creature.c, misc1.c: breath(), update_mon(), and loc_symbol() changed to use blind status bit instead of blind counter, this helps make the display look better, i.e. nothing disappears until blindness takes affect in dungeon.c monsters.c: more monster fixes from DJG monsters.c, misc1.c, moria2.c, treasur1.c: change (SM) to (SA), slay monster to slay animal monsters.c: set the new 'animal' bit correctly for all monsters recall.c: change 'unnatural creature' to 'natural creature', change a few constants to defines save.c: add error exits to every loop/array index in the get_char() routine to prevent crashes due to bad save files store1.c: in item_value, set value to zero if known cursed, this prevents store from buying known cursed items ------------ 12/7 store2.c: remove switches in prt_comment*() functions, replace with table look up to get proper string, saves much code space creature.c: changed stealth code again, if resting/paralyzed monster has a chance of noticing once every 50 turns instead of never like before, change 64 to 1024, and 17 to 29 for a better distribution constant.h, save.c: read noscore variable from savefile of dead character, now only read/write noscore for live characters, changed patch_level to 9 so that old savefiles can still be read save.c: in get_char(), the loop error prevention code was missing two gotos store2.c: get_haggle(), when check for valid first use of incremental haggle, ignore leading spaces in the string moria2.c: add_food() should increment slow value, not just set it when bloated save.c: when can't create savefile, test for from_savefile before giving wizard message "Overwrite old?", when exit in wizard mode do the "readable to all?" check after closing the file save.c: from_savefile set wrong, should always be set if have read from a file not just when a complete character is read moria2.c: bash(), do not put character off balance if bash is successful misc2.c: get_spell(), instead of beeping for unknown spell, print a message recall.c: for monsters with sleep value of 0, could never learn that fact, change it so that this will be known if have killed 10 of them -----12/9 dungeon.c: call disturb when player takes poison damage, or starvation damage variable.c: change the three doors from 'a ...' to '& ...', needed because of wall-to-mud wand wizard.c: create_object wrong, was calling popt() then delete_object() then setting c_ptr->tptr, this fails because the delete objects will move the location (in t_list) of the just created object will change treasur2.c: change 'nothing' item to be stackable, so that it can be safely picked up save.c: was calling store_maint before objects were reidentified, this caused stores to end up with multple entries for stackable identified items externs.h, misc2.c: new function inven_check_weight(), check toosee whether picking up an object will change the players speed moria2.c: carry(), if picking up an object would slow you down, prompt with question "Exceed your weight limit?" to give player a choice moria2.c, misc1.c: only show rock types in look() if highlight_seams option is set, also change option text from "highlight" to "HL and notice" spells.c: in fire_bolt() and fire_ball(), set recall info if monster takes extra damage because of weakness or reduced damage because of breath, in dispel_creature() set EVIL/UNDEAD flag if creature hurt, in turn_undead() set UNDEAD if creature hurt, in drain_life() set CD_UNDEAD if creature not hurt recall.c: "may carry one or two treasures" needs the plural, but the others remain singular/collective ------------- 12/11 creature.c: stealth value changed again from 125 to 100 wizard.c, variable.c: change rogue base stealth from 4 to 5, let wizard set stealth to 18 monster.c: white worm mass sleep value from 10 to 1, crystal ooze 60 -> 1 creature.c: in drain mana spell, if r1 greater than cmana, then set r1 equal to cmana to limit creature's hp gain recall.c: when print out creature attacks, exit loop if i >= 4, caused problems for umber hulk, etc. which have 4 attacks store1.c: instead of destroying all single stackable objects, only destroy one half on average (randint(number)), makes store 1 and 5 inventories look better, oil is much more common, identify a little more common treasure2.c: accidentally change blank_treasure tval earlier, set tval back to 0, and set subval to 64 store1.c: change store_carry(), for group items, must update scost; for any stackable item, set ipos so that inventory will scroll to show it; let group items (except torches) stack over 24 since each group is created with a set number to begin with; ipos must be set to -1 at start not 0; store2.c: store_sell(), pass a pointer to cur_top instead of just its value, if sold object not on the page shown, scroll to show the object ------------ 12/13 recall.c: only print out known attacks, i.e. check r_attack, change i to count from 0 to 3, fixes bug with knowdamage(), add variable j to count attacks actually printed out save.c: put limit on number of times store inventory changed in get_char() store2.c: rewrite incremental haggle code again, add new parameter 'num_offer' to receive_offer, change get_offer parm last_offer to num_offer, only allow inc haggle if num_offer != 0; must reset new_offer after rejected offer in recieve_offer and sell/purchase_haggle ------------ 12/14 misc2.c, lots: change way spell learning works, new command 'G'ain magic spells, new function gain_spells() in misc2.c formerly part of calc_spells(), new status flag PY_STUDY controls printing of 'Study' in status line, new field py.flags.new_spells number of spells can learn origcmds.hlp, roglcmds.hlp: document the 'M'ap and 'G'ain magic commands variables.c, potions.c: remove potion of learning as it is no longer useful moria-5.6.debian.1/vms/0000755000175000017500000000000011074757460013003 5ustar pjbpjbmoria-5.6.debian.1/vms/getch.c0000644000175000017500000001252211074756221014235 0ustar pjbpjb/* vms/getch.c: input routines for VMS, integrated with smcurses for VMS Copyright (c) 1986-94 Joshua Delahunty, James E. Wilson This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include #include #include #include #ifndef TRUE # define TRUE 1 # define FALSE 0 #endif /* the type of keyboard read we're doing */ #define FUNC IO$_TTYREADALL|IO$M_NOECHO|IO$M_TRMNOECHO static $DESCRIPTOR(chan, "tt:"); static char ungotch; static unsigned short int kb_chan = 0; /* channel # */ static unsigned short int charwaiting = FALSE, crmode_status = TRUE, echo_status = FALSE; /* This code was tested and worked on a VAX 11/785 running VMS 5.2. contributed by Ralph Waters, rwaters@jabba.ess.harris.com. */ /* Returns 1 is a character has been pressed, 0 otherwise. */ int kbhit() { /* sys$qiow ( [efn] ,chan ,func [,iosb] [,astadr] [,astprm] [,p1] [,p2] [,p3] [,p4] [,p5] [,p6] ) */ /* The sys$qiow call with the IO$_SENSEMODE|IO$M_TYPEAHDCNT function will return the following in p1: 31 24 23 16 15 0 ------------|------------|------------------------ | reserved | first | number of characters | | | character | in type-ahead buffer | |-----------|------------|-----------------------| | reserved | | | -------------------------------------------------- */ struct qio_return_type { unsigned short int type_ahead_count; /* type-ahead count */ unsigned char first_char; /* first character in buffer */ unsigned char b_reserved; /* reserved byte */ unsigned long int l_reserved; } /* reserved long word */ qio_return; sys$qiow (0, kb_chan, (IO$_SENSEMODE | IO$M_TYPEAHDCNT), 0, 0, 0, &qio_return, 0, 0, 0, 0, 0); if (qio_return.type_ahead_count > 0) return(1); else return(0); } /* Another useful function courtesy of Ralph Waters. */ #include /* Stores the user's login name in the argument buf. */ void user_name(buf) char *buf; { /* sys$getjpiw ( [efn], [pidadr], [prcnam], itmlst [,iosb] [,astadr] [,astprm] */ long int return_length; struct getjpi_itmlst_type { unsigned short int buffer_length; /* length of return buffer */ unsigned short int item_code; /* item code to getjpi about */ unsigned long int buffer_address; /* address of return data */ unsigned long int return_length_addr; } /*actual size of return data */ getjpi_itmlst; getjpi_itmlst.buffer_length = 12; /* VMS usernames are 12 chars */ getjpi_itmlst.item_code = JPI$_USERNAME; getjpi_itmlst.buffer_address = buf; getjpi_itmlst.return_length_addr = &return_length; sys$getjpiw (0, 0, 0, &getjpi_itmlst, 0, 0, 0); return; } /* After calling this, vms_getch() returns unbuffered single chars. */ void vms_crmode() /* Character-Return MODE */ { if(kb_chan == 0) opengetch(); crmode_status = TRUE; } /* After calling this, vms_getch() returns echoed, buffered characters. */ void vms_nocrmode() /* NO Character-Return MODE */ { if(kb_chan != 0) closegetch(); crmode_status = FALSE; } /* Sets up terminal for getch() calls, returns VMS status code. */ int opengetch() /* does the actual assignment work */ { /* assign channel on keyboard */ return(sys$assign(&chan,&kb_chan,0,0)); } /* Undoes affects of above, returns VMS status code for the operation. */ int closegetch() /* performs the actual deassignment work */ { int rv; if(kb_chan != 0) { /* deassign keyboard channel */ rv = sys$dassgn(kb_chan); kb_chan = 0; return(rv); } } /* Returns an [optionally] unbuffered [non-]echoed input character. If crmode_status is not set, then the code returns one character from the buffered input. If crmode_status is set, then the code returns an `ungot' character if one exists, otherwise it tries to read one unbuffered character from the keyboard. If echo_status is set, then the character will be echoed before returning. */ char vms_getch() { int rv; char kb_buf; /* buffer for input char */ if(crmode_status) { if(!charwaiting) { /* open channel if it hasn't been done already */ if (kb_chan == 0) opengetch(); /* que an i/o request for a character and wait */ rv = sys$qiow(0,kb_chan,FUNC,0,0,0,&kb_buf,1,0,0,0,0); /* indicate if something is amiss */ if(rv != SS$_NORMAL) { printf("?"); exit(rv); } } else { /* charwaiting */ kb_buf = ungotch; charwaiting = FALSE; } /* massage for getchar() compatibility */ if (kb_buf == '\r') kb_buf='\n'; /* echo char if we're supposed to */ if (echo_status) putchar(kb_buf); return(kb_buf); } else /* nocrmode */ return(getchar()); } moria-5.6.debian.1/vms/ERRORS0000644000175000017500000000174005613574177013750 0ustar pjbpjbwhy does the VMS port need its own versions of the curses functions in cbreak.c and getch.c? files.c needs two restore_screen() calls to work properly? clear_screen() in shell_out() after return from spawned process does not clear screen properly? if is only included in files.c, and errno is defined in externs.h, then there is a 'psect' problem with errno? ESCAPE is defined as Control-Z for compatibility with the VMS Moria versions, but this is not documented anywhere, note the define for ESCAPE in constant.h ! and $ commands are aliases, but this is not documented curses puts vtxxx keypad into application mode, inkey() has some code to convert keypad escape sequences back into numbers, this code may cause strange behaviour if someone types a real ESCAPE character, why does curses put the keypad in application mode in the first place? refresh() and clear() do not seem to work right, note the contorted code in inkey() and clear_screen() to make these work right moria-5.6.debian.1/vms/uexit.c0000644000175000017500000000240211074756221014275 0ustar pjbpjb/* vms/uexit.c: special exit command, to exit cleanly from VMS program. Copyright (c) 1990-94 Joshua Delahunty, James E. Wilson This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ /* Unix programs usually return 0 for "good execution", and 1 for "some problem occured." In VMS, we WANT the program to return a 1, or else we get an ugly "%NONAME-W-NOMSG, Message number 00000000" message upon image exit (yeech!). So, we convert 0 exit codes to 1's, leaving all others alone. */ void uexit(exitcode) int exitcode; { if (exitcode == 0) /* On Unix, clean, on VMS, yeech! */ exit(1); /* converted... */ else exit(exitcode); /* returned unscathed... */ } moria-5.6.debian.1/vms/descrip.mms0000644000175000017500000000502705613574200015145 0ustar pjbpjbMORIA.EXE : MAIN.OBJ, CREATE.OBJ, CREATURE.OBJ, DEATH.OBJ, - DESC.OBJ, DUNGEON.OBJ, EAT.OBJ, FILES.OBJ, GENERATE.OBJ, - GETCH.OBJ, HELP.OBJ, IO.OBJ, MAGIC.OBJ, MAIN.OBJ, MISC1.OBJ, - MISC2.OBJ, MISC3.OBJ, MISC4.OBJ, MONSTERS.OBJ, MORIA1.OBJ, - MORIA2.OBJ, MORIA3.OBJ, MORIA4.OBJ, PLAYER.OBJ, - POTIONS.OBJ, PRAYER.OBJ, RECALL.OBJ, RND.OBJ, SAVE.OBJ, SCROLLS.OBJ, - SETS.OBJ, SIGNALS.OBJ, SPELLS.OBJ, STAFFS.OBJ, STORE1.OBJ, - STORE2.OBJ, TABLES.OBJ, TREASURE.OBJ, UEXIT.OBJ, - VARIABLE.OBJ, WANDS.OBJ, WIZARD.OBJ - $(link) $(linkflags) MORIA.OPT/opt create.obj : constant.h, types.h, externs.h, config.h creature.obj : constant.h, types.h, externs.h, config.h death.obj : constant.h, types.h, externs.h, config.h desc.obj : constant.h, types.h, externs.h, config.h dungeon.obj : constant.h, types.h, externs.h, config.h eat.obj : constant.h, types.h, externs.h, config.h files.obj : constant.h, types.h, externs.h, config.h generate.obj : constant.h, types.h, externs.h, config.h help.obj : constant.h, types.h, externs.h, config.h io.obj : constant.h, types.h, externs.h, config.h magic.obj : constant.h, types.h, externs.h, config.h main.obj : constant.h, types.h, externs.h, config.h misc1.obj : constant.h, types.h, externs.h, config.h misc2.obj : constant.h, types.h, externs.h, config.h misc3.obj : constant.h, types.h, externs.h, config.h misc4.obj : constant.h, types.h, externs.h, config.h monsters.obj : constant.h, types.h, config.h moria1.obj : constant.h, types.h, externs.h, config.h moria2.obj : constant.h, types.h, externs.h, config.h moria3.obj : constant.h, types.h, externs.h, config.h moria4.obj : constant.h, types.h, externs.h, config.h player.obj : constant.h, types.h, config.h potions.obj : constant.h, types.h, externs.h, config.h prayer.obj : constant.h, types.h, externs.h, config.h recall.obj : constant.h, config.h, types.h, externs.h rnd.obj : constant.h, types.h save.obj : constant.h, types.h, externs.h, config.h scrolls.obj : constant.h, types.h, externs.h, config.h sets.obj : constant.h, config.h signals.obj : constant.h, types.h, externs.h, config.h spells.obj : constant.h, types.h, externs.h, config.h staffs.obj : constant.h, types.h, externs.h, config.h store1.obj : constant.h, types.h, externs.h, config.h store2.obj : constant.h, types.h, externs.h, config.h tables.obj : constant.h, types.h, config.h treasure.obj : constant.h, types.h, config.h variable.obj : constant.h, types.h, config.h wands.obj : constant.h, types.h, externs.h, config.h wizard.obj : constant.h, types.h, externs.h, config.h moria-5.6.debian.1/vms/Makefile0000644000175000017500000001051205613574176014445 0ustar pjbpjb# COPTS = /nowarning COPTS = OBJS1 = create.obj creature.obj death.obj desc.obj dungeon.obj eat.obj \ files.obj generate.obj getch.obj help.obj io.obj magic.obj main.obj \ misc1.obj misc2.obj misc3.obj misc4.obj monsters.obj OBJS2 = moria1.obj moria2.obj moria3.obj moria4.obj player.obj potions.obj \ prayer.obj recall.obj rnd.obj save.obj scrolls.obj sets.obj \ signals.obj spells.obj staffs.obj store1.obj store2.obj tables.obj OBJS3 = treasure.obj uexit.obj variable.obj wands.obj wizard.obj moria : $(OBJS1) $(OBJS2) $(OBJS3) link moria/opt create.obj : create.c constant.h types.h externs.h config.h cc $(COPTS) create.c /obj=create.obj creature.obj : creature.c constant.h types.h externs.h config.h cc $(COPTS) creature.c /obj=creature.obj death.obj : death.c constant.h types.h externs.h config.h cc $(COPTS) death.c /obj=death.obj desc.obj : desc.c constant.h types.h externs.h config.h cc $(COPTS) desc.c /obj=desc.obj dungeon.obj : dungeon.c constant.h types.h externs.h config.h cc $(COPTS) dungeon.c /obj=dungeon.obj eat.obj : eat.c constant.h types.h externs.h config.h cc $(COPTS) eat.c /obj=eat.obj files.obj : files.c constant.h types.h externs.h config.h cc $(COPTS) files.c /obj=files.obj generate.obj : generate.c constant.h types.h externs.h config.h cc $(COPTS) generate.c /obj=generate.obj getch.obj : getch.c cc $(COPTS) getch.c /obj=getch.obj help.obj : help.c constant.h types.h externs.h config.h cc $(COPTS) help.c /obj=help.obj io.obj : io.c constant.h types.h externs.h config.h cc $(COPTS) io.c /obj=io.obj magic.obj : magic.c constant.h types.h externs.h config.h cc $(COPTS) magic.c /obj=magic.obj main.obj : main.c constant.h types.h externs.h config.h cc $(COPTS) main.c /obj=main.obj misc1.obj : misc1.c constant.h types.h externs.h config.h cc $(COPTS) misc1.c /obj=misc1.obj misc2.obj : misc2.c constant.h types.h externs.h config.h cc $(COPTS) misc2.c /obj=misc2.obj misc3.obj : misc3.c constant.h types.h externs.h config.h cc $(COPTS) misc3.c /obj=misc3.obj misc4.obj : misc4.c constant.h types.h externs.h config.h cc $(COPTS) misc4.c /obj=misc4.obj monsters.obj : monsters.c constant.h types.h config.h cc $(COPTS) monsters.c /obj=monsters.obj moria1.obj : moria1.c constant.h types.h externs.h config.h cc $(COPTS) moria1.c /obj=moria1.obj moria2.obj : moria2.c constant.h types.h externs.h config.h cc $(COPTS) moria2.c /obj=moria2.obj moria3.obj : moria3.c constant.h types.h externs.h config.h cc $(COPTS) moria3.c /obj=moria3.obj moria4.obj : moria4.c constant.h types.h externs.h config.h cc $(COPTS) moria4.c /obj=moria4.obj player.obj : player.c constant.h types.h config.h cc $(COPTS) player.c /obj=player.obj potions.obj : potions.c constant.h types.h externs.h config.h cc $(COPTS) potions.c /obj=potions.obj prayer.obj : prayer.c constant.h types.h externs.h config.h cc $(COPTS) prayer.c /obj=prayer.obj recall.obj : recall.c constant.h types.h externs.h config.h cc $(COPTS) recall.c /obj=recall.obj rnd.obj : rnd.c constant.h types.h cc $(COPTS) rnd.c /obj=rnd.obj save.obj : save.c constant.h types.h externs.h config.h cc $(COPTS) save.c /obj=save.obj scrolls.obj : scrolls.c constant.h types.h externs.h config.h cc $(COPTS) scrolls.c /obj=scrolls.obj sets.obj : sets.c constant.h config.h cc $(COPTS) sets.c /obj=sets.obj signals.obj : signals.c constant.h types.h externs.h config.h cc $(COPTS) signals.c /obj=signals.obj spells.obj : spells.c constant.h types.h externs.h config.h cc $(COPTS) spells.c /obj=spells.obj staffs.obj : staffs.c constant.h types.h externs.h config.h cc $(COPTS) staffs.c /obj=staffs.obj store1.obj : store1.c constant.h types.h externs.h config.h cc $(COPTS) store1.c /obj=store1.obj store2.obj : store2.c constant.h types.h externs.h config.h cc $(COPTS) store2.c /obj=store2.obj tables.obj : tables.c constant.h types.h config.h cc $(COPTS) tables.c /obj=tables.obj treasure.obj : treasure.c constant.h types.h config.h cc $(COPTS) treasure.c /obj=treasure.obj uexit.obj : uexit.c constant.h types.h config.h cc $(COPTS) uexit.c /obj=uexit.obj variable.obj : variable.c constant.h types.h externs.h config.h cc $(COPTS) variable.c /obj=variable.obj wands.obj : wands.c constant.h types.h externs.h config.h cc $(COPTS) wands.c /obj=wands.obj wizard.obj : wizard.c constant.h types.h externs.h config.h cc $(COPTS) wizard.c /obj=wizard.obj moria-5.6.debian.1/vms/README0000644000175000017500000000311505613574177013667 0ustar pjbpjbNOTE: ESCAPE is defined as Control-Z in constant.h to be more like the original VMS moria, this is not documented anyplace, so whenever the doc/program says escape type control_Z instead. If you don't like this, delete the define for escape in constant.h (but you will probably have to hit escape twice for it to work). If you're building Moria on a VAX/VMS system, you'll need a C compiler that understands the 'defined()' macro. Notes on VMS files: getch.c - single character terminal input and related routines. uexit.c - shell for the exit() call, to prevent -NOMSG messages from appearing when exiting the Moria program. makefile. - for use if you have a Make utility. I use Todd Aven's VMSMAKE (with the unix options) moria.opt - the options file for linking Moria. (You do a 'link moria/opt' command to link the program) descrip.mms - builds moria if you have the mms utility. (You do a 'mms/description=descrip.mms' to build it.) debug.mms - builds moria to run under debug if you have the mms utility. (You do a 'mms/description=debug.mms' to build the debugger version.) make.com - for those without make or mms, does all the compiles and the final link of the program. scores.fdl - file intended for use with CONVERT/FDL; the score file needs to be created empty, then converted using scores.fdl. This is because moria expects it to be stream/LF format. In the config.h file, the files that moria uses are defined to be on the logical device 'moria:'. This will need to be defined before you can run Moria. moria-5.6.debian.1/vms/debug.mms0000644000175000017500000000510005613574177014607 0ustar pjbpjbcflags = /NOOPT/DEBUG linkflags = /DEBUG MORIA.EXE : MAIN.OBJ, CREATE.OBJ, CREATURE.OBJ, DEATH.OBJ, - DESC.OBJ, DUNGEON.OBJ, EAT.OBJ, FILES.OBJ, GENERATE.OBJ, - GETCH.OBJ, HELP.OBJ, IO.OBJ, MAGIC.OBJ, MAIN.OBJ, MISC1.OBJ, - MISC2.OBJ, MISC3.OBJ, MISC4.OBJ, MONSTERS.OBJ, MORIA1.OBJ, - MORIA2.OBJ, MORIA3.OBJ, MORIA4.OBJ, PLAYER.OBJ, - POTIONS.OBJ, PRAYER.OBJ, RECALL.OBJ, RND.OBJ, SAVE.OBJ, SCROLLS.OBJ, - SETS.OBJ, SIGNALS.OBJ, SPELLS.OBJ, STAFFS.OBJ, STORE1.OBJ, - STORE2.OBJ, TABLES.OBJ, TREASURE.OBJ, UEXIT.OBJ, - VARIABLE.OBJ, WANDS.OBJ, WIZARD.OBJ - $(link) $(linkflags) MORIA.OPT/opt create.obj : constant.h, types.h, externs.h, config.h creature.obj : constant.h, types.h, externs.h, config.h death.obj : constant.h, types.h, externs.h, config.h desc.obj : constant.h, types.h, externs.h, config.h dungeon.obj : constant.h, types.h, externs.h, config.h eat.obj : constant.h, types.h, externs.h, config.h files.obj : constant.h, types.h, externs.h, config.h generate.obj : constant.h, types.h, externs.h, config.h help.obj : constant.h, types.h, externs.h, config.h io.obj : constant.h, types.h, externs.h, config.h magic.obj : constant.h, types.h, externs.h, config.h main.obj : constant.h, types.h, externs.h, config.h misc1.obj : constant.h, types.h, externs.h, config.h misc2.obj : constant.h, types.h, externs.h, config.h misc3.obj : constant.h, types.h, externs.h, config.h misc4.obj : constant.h, types.h, externs.h, config.h monsters.obj : constant.h, types.h, config.h moria1.obj : constant.h, types.h, externs.h, config.h moria2.obj : constant.h, types.h, externs.h, config.h moria3.obj : constant.h, types.h, externs.h, config.h moria4.obj : constant.h, types.h, externs.h, config.h player.obj : constant.h, types.h, config.h potions.obj : constant.h, types.h, externs.h, config.h prayer.obj : constant.h, types.h, externs.h, config.h recall.obj : constant.h, config.h, types.h, externs.h rnd.obj : constant.h, types.h save.obj : constant.h, types.h, externs.h, config.h scrolls.obj : constant.h, types.h, externs.h, config.h sets.obj : constant.h, config.h signals.obj : constant.h, types.h, externs.h, config.h spells.obj : constant.h, types.h, externs.h, config.h staffs.obj : constant.h, types.h, externs.h, config.h store1.obj : constant.h, types.h, externs.h, config.h store2.obj : constant.h, types.h, externs.h, config.h tables.obj : constant.h, types.h, config.h treasure.obj : constant.h, types.h, config.h variable.obj : constant.h, types.h, config.h wands.obj : constant.h, types.h, externs.h, config.h wizard.obj : constant.h, types.h, externs.h, config.h moria-5.6.debian.1/vms/make.com0000644000175000017500000000231405613574177014424 0ustar pjbpjb$ set verify $ cc create.c /obj=create.obj $ cc creature.c /obj=creature.obj $ cc death.c /obj=death.obj $ cc desc.c /obj=desc.obj $ cc dungeon.c /obj=dungeon.obj $ cc eat.c /obj=eat.obj $ cc files.c /obj=files.obj $ cc generate.c /obj=generate.obj $ cc help.c /obj=help.obj $ cc io.c /obj=io.obj $ cc magic.c /obj=magic.obj $ cc main.c /obj=main.obj $ cc misc1.c /obj=misc1.obj $ cc misc2.c /obj=misc2.obj $ cc misc3.c /obj=misc3.obj $ cc misc4.c /obj=misc4.obj $ cc monsters.c /obj=monsters.obj $ cc moria1.c /obj=moria1.obj $ cc moria2.c /obj=moria2.obj $ cc moria3.c /obj=moria3.obj $ cc moria4.c /obj=moria4.obj $ cc potions.c /obj=potions.obj $ cc player.c /obj=player.obj $ cc prayer.c /obj=prayer.obj $ cc recall.c /obj=recall.obj $ cc rnd.c /obj=rnd.obj $ cc save.c /obj=save.obj $ cc scrolls.c /obj=scrolls.obj $ cc sets.c /obj=sets.obj $ cc signals.c /obj=signals.obj $ cc spells.c /obj=spells.obj $ cc staffs.c /obj=staffs.obj $ cc store1.c /obj=store1.obj $ cc store2.c /obj=store2.obj $ cc tables.c /obj=tables.obj $ cc treasure.c /obj=treasure.obj $ cc variable.c /obj=variable.obj $ cc wands.c /obj=wands.obj $ cc wizard.c /obj=wizard.obj $ cc getch.c /obj=getch.obj $ cc uexit.c /obj=uexit.obj $ link moria/opt moria-5.6.debian.1/vms/scores.fdl0000644000175000017500000000106705613574200014763 0ustar pjbpjbIDENT "12-JUL-1990 11:05:15 VAX-11 FDL Editor" SYSTEM SOURCE "VAX/VMS" FILE BEST_TRY_CONTIGUOUS no CLUSTER_SIZE 3 CONTIGUOUS no EXTENSION 0 FILE_MONITORING no GLOBAL_BUFFER_COUNT 0 ORGANIZATION sequential PROTECTION (system:RWED, owner:RWED, group:, world:RW) RECORD BLOCK_SPAN yes CARRIAGE_CONTROL carriage_return FORMAT stream_LF moria-5.6.debian.1/vms/moria.opt0000644000175000017500000000136205613574176014643 0ustar pjbpjbMAIN.OBJ, - CREATE.OBJ, - CREATURE.OBJ, - DEATH.OBJ, - DESC.OBJ, - DUNGEON.OBJ, - EAT.OBJ, - FILES.OBJ, - GENERATE.OBJ, - GETCH.OBJ, - HELP.OBJ, - IO.OBJ, - MAGIC.OBJ, - MISC1.OBJ, - MISC2.OBJ, - MISC3.OBJ, - MISC4.OBJ, - MONSTERS.OBJ, - MORIA1.OBJ, - MORIA2.OBJ, - MORIA3.OBJ, - MORIA4.OBJ, - PLAYER.OBJ, - POTIONS.OBJ, - PRAYER.OBJ, - RECALL.OBJ, - RND.OBJ, - SAVE.OBJ, - SCROLLS.OBJ, - SETS.OBJ, - SIGNALS.OBJ, - SPELLS.OBJ, - STAFFS.OBJ, - STORE1.OBJ, - STORE2.OBJ, - TABLES.OBJ, - TREASURE.OBJ, - UEXIT.OBJ, - VARIABLE.OBJ, - WANDS.OBJ, - WIZARD.OBJ, - SYS$LIBRARY:VAXCRTl/share ! ^ char input ! ^ small stubs for cbreak(), nocbreak() ! ^ small stub for exit() call ! ^ links us with the RTLibrary moria-5.6.debian.1/ERRORS0000644000175000017500000011210705613574174013140 0ustar pjbpjb black ooze should resist acid, but can't code this because it casts spells and would breathe acid if it were given acid resistance identifying items by one-digit inscriptions should work for items in equipment list as well as for items in inventory saving and restoring takes a turn, this can be fatal in combat ----JEW's old ERRORS list, excluding things fixed by DJG stores probably should buy items which have been marked {damned} by being worn and then cleared via remove curse, after all they buy unident damned items creating traps can destroy staircases chests should create treasure appropriate to the level they were found on, or to the level of the chest, not the level that they are opened on color MacMoria bugs: the colors dialog box says greed not green the help dialog lists the wrong versions my address is wrong when wearing a ring of speed, light should not be used up as fast, the faster you are moving, the more turns it should last - by the same reasoning, store lockout are broken too, in fact just about anything using time won't work `correctly' when character is sped up calling put_qio() every turn during running significantly slows it down on slow hosts which are using curses, I believe it was added only for aesthetics, and it probably isn't strictly necessary, could at least surround it with an #ifndef FAST_RUNNING or similar when thief steals an object, say what was stolen in message when item in backpack is destroyed, indicate what item was destroyed inventory does not take a turn display_scores(), at end of the game, should display top 15 or so scores, and list the current player's score below that if not in the top 15 list, at least, the value of show_player should be false at the end - better, display_scores can put a message line at the bottom like this ( ESC : return to game space : toggle all scores/your scores) and then the player can easily choose which scores to see the 32767 limit in the recall code for number of monsters killed is too easy to reach, making it unsigned will extend the range to 65535, making it a long would increase program size by 2K, I don't think that this change is worth the extra memory used Mac: choosing `9 point' from the screen menu results in a 1" square window which won't expand or grow, switching back to 12 point gives a huge window with type that appears to be about 100 points or so monsters should probably not be summoned on top of a rune of protection could make scorefile code more efficient if I read/write more than one entry at a time for MSDOS: shouldn't the treasure.c file change '#' to wallsym, and '.' to floorsym?, shouldn't the save.c file change '.' to floorsym and vice versa, just like it already does for wallsym? VMS curses apparently has a bug, during resting, the program continually moves the cursor to the @ sign, which is a no-op and should result in no output, but the VMS curses code outputs control commands to the terminal, this makes resting run slow on bandwidth limited terminals VMS has 32 bit user ids (UIC), should increase the size of uid's in the scorefile to 32 bits, and then make the vms uic = getgid()<<16+getuid() which is 32 bits remove the hours support for all micros, or else give people the option in the config.h file to remove it when functions are not used, ifdef out the calls instead of providing dummy functions, to save some space save.c creates two files under VMS, because it first calls 'open' and then later calls 'fopen', rewrite so that only one file will be created in store.c, the comment "Your mother was a troll!" doesn't mean anything if you are a half-troll, change to Ogre? the ms_misc.c file maps the 'Ins' key, which is the '0' key to 'i', this confuses the hell out of a lot of people, this IS documented, but few people read the documentation add a turns counter to the higscores entry, and check this when restoring a character, don't score the character if this value is different this prevents someone from playing a character, goofing, saving it while alive, and then going back to the first savefile haste self is a level 1 potion, and super heroism is level 3, both seem far too low of a level for the potions considering how useful they are, increasing the levels would make them more common deeper in the dungeon restore potions are level 40 are too deep, they are available in the stores, and just aren't that powerful of a potion DJG: haste self is needed at level 1 for early encounters with nasty monsters super heroism could be higher the sorting code does not work with foodstuffs, problem is that when restore a 5.2.1 character which has unsorted food, the new code may put a food ration at the start instead of merging it with the other unsorted food, thus overflowing the inventory size, there are few 5.2.1 characters left anyways, so perhaps this isn't much of a problem anymore wine/ale should be potions to be quaffed, not foodstuffs to be eaten ^M = ^J when digging, can't really solve well, because of bugs in some version of curses which requires this to be true perhaps add an option to control the Drop One/Drop All query for multiple stacking items the choice of whether or not duplicate characters should be scored should really be an option in the config.h file, since there exist single-user unix machines, and multi-user IBM-PCs (on a network) - also, the decision of whether to limit each player to one entry per character type should be an option (perhaps the same one) give warriors a better chance of detecting that ego weapons are magik, but only for ego weapons, not all items an inscription is lost when two objects are merged, either choose longest, or ask player, try to combine them, at least do something Macintosh - mac version does not clear screen after saving a character restart variables are not reset as they should (maybe fixed?) - mac moria crashes with the 384 size resource?, works fine with 512k size - mac moria crashes when trying to write past the end of the screen, specifically, if have a weapon with more than 80 characters, and put it last in the equipment list, then mac version will crash add code to put_buffer to truncate strings? - the CRuntime.o and CLibraries.o ARE needed for the mac makefiles. - the file type and creator are not set for the character stats file - when save a game and hit the cancel button, it still says the game is being saved even though it isn't - when a character dies, the savefile is not marked as dead - should be able to find config file in same directory as the program - should get version number from constants, not hardwired into resources - should have color menu enabled even on B&W monitor, so you can switch black and white if desired - does not work on 512K mac, seems to be enough memory, but it uses routines which are not in the old ROMS, 512K macs are obsolete, so this is probably not worth fixing IBMPC - received report that -w command gives 'file from wrong version' error - when followed by monster, and reach edge of screen, sometimes the game hangs and you must type a character for it to continue, either a Turbo C bug or a PC-Moria bug - tunneling does not work with the numeric keypad when using rogue-like mode, i.e. ctrl-4 - on PC, only draw during traceback, perhaps make this an option, this is a CGA specific problem (most people have VGA now a days), and only applies to the Turbo C builtin screen code, tcio.c, PC-Curses does not have this problem, in Turbo Pascal, there is a variable in the CRT unit that one can set to enable this feature - tcio.c file does not handle redraw ^R at all run under Saber C to see if that turns up any bugs - if you curse a special magic item (HA, RF, etc), it retains its very high value, its cost should be reset to the value in object_list[index] - if you curse a special cursed object (noise, irritation), it will lose its special cursed ability (two wrongs make a right?!?), this should not happen, instead of clearing ALL flag bits, should only clear the 'good' ones if wield a torch, and a silver jelly immediately drains it to 1, the program will be confused for one turn thinking that you still have light even though you don't scoring unfair to humans/warriors/etc, since they have a lower max exp than other race/classes, should adjust exp downward by inflationary factors when calculating score? DJG: unnecessary should reduce stack usage in generate.c in the store, should have some way to determine how close one is to getting perfect haggling replace all of those heavy weapon messages with an automatic inscription, how should this be maintainted, should it change only when wielded, or should it change whenever the players strength changes? throwing a lot of objects into a pile can cause problems? make the printing of stuff under monsters an option for those who find it bothersome make monster movement more intelligent: - for slow monsters, in movement_rate(), instead of using mod, use (randint(2 - speed) == 1) to make monster movement a little more uncertain for fast monsters, give a little variance to speed, i.e. 66% of time monster moves at speed, 17% of time move at speed+1, 17% of time move at speed-1 - monsters which are about to die should flee if intelligent - monsters should breathe at player if only separated by a single column - better spell selection, don't cast teleport_to when standing next to player, etc. - have monsters with multiple attacks spread the attacks over each turn if moving slower than player, instead of doing nothing one turn, and then attacking multiple times on the next turn - remember the previous two moves for each intelligent monster, so they can tell which direction they are moving in get_com(), get_dir(), etc, put -escape- on the msg line if escape key pressed, useful if message doesn't get deleted, but doesn't this always happen?, apparently not on the Atari ST MWC port rubble can be generated underneath a monster, which should not happen why call sigsetmask(0)? delete signals() and nosignals() as unnecessary? killing a shell -1 results in the game disappearing without leaving a save file, what happened? the save.c code that says "file exists, overwrite?", can this ever be executed?, if so, does it do the right thing?, and also, what happens on EOF? will it go into an infinite loop on EOF? what exactly does the damned flag mean, should it be on for all except known2 items, or should it be on when an item is known to be cursed? add ptodam to damage before calling critical_hits - modify C command to print to dam bonuses modified by weapon, should print both the unmodified bonus, and the modified bonus - should take about 10 slay dragon arrows to kill AMHD, check this after ptodam code is changed, may need to increase damages from +3? - also check other ego weapons for play balance, maybe reduce ego multipliers when rogues list Beginners Majik spell book, spells are listed 'a'-'e', when cast from the spell book, spells are listed 'b'-'f', the spell casting list should also go from 'a'-'e', but this looks hard to fix allow SPACE to exit from inventory commands no monster, except Balrog, can resist mass polymorph, should I make it more like polymorph? mass polymorph is much higher level than polymorph, and is useful for dire emergencies, either don't give monsters a saving throw, or make is something like level/(3*MAX_MONS_LEVEL/2) which will make it possible but not certain that the staff will work on AMHD's should mac port have a separate io.c file? 'headless' monsters should not glare when recovering from a bash version.inf file should not contain version number/copyright, these should be printed from the variable values in misc1.c, the pusht code requires search of entire cave structure, this needs to be written more efficiently, perhaps put x,y into inven_type for every object located somewhere in the cave? eliminate all #if 0 in the code ************************** Changes that can wait... only let warriors get *GREAT* hits? in critical_hits(), change the threshholds to 400-600-800, which will make all melee weapons eligible for great hits, and only let warriors get great hits since this makes Mage's much worse fighters, swap Sleep II for Lightning Ball (giving a much needed intermediate Ball spell), and Recharge I for Object Dectection (to compensate for Priest's sense surroundings) DJG: object detection isn't very useful increase the classes of weapons from 3 to 5, i.e. missile, blunt, assassin, melee (two handed weapons, etc., only these can do *GREAT* hits), and normal. Then modify fighting abilities as follows: mis blu ass mel nor a) b) c) d) e) -- := suck Warrior + + + ++ + - := iffy Rogue + 0 ++ - 0 0 := unchanged Mage 0 0 0 -- 0 + := improved Ranger ++ 0 0 0 0 ++ := hyperb Priest 0 + - -- 0 Paladin 0 ++ 0 0 0 the monster memory always prints monster attack types and damage types together, this can lead to strange situations, for example, if a grey mushroom patch releases spores, but does not confuse the player, nothing appears in the monster memory because the player does not know they were confusion spores, but he/she does know that that spores are released IBMPC COLOR - the experimental color support for PC-Moria does not work well when trying to display a monster which is the same color as the background - the disenchanter w and b are not the same color - CHP changes to the same color as ball/breath that lowered it - all mushrooms are wrong, except the grey mushroom patch - invisible monsters can easily be found by casting stinking cloud at the walls which will color all spaces green, except the one with the invisible monster show how many spells player can learn via the 'G' command add max mana to display in addition to current mana add inscriptions that apply to a class of objects, not just a single instance shouldn't be able to genocide invalid letters; escape out of genocide have alternative messages to 'dies in a fit of agony', that gets a bit repetitive, and boring a command to allow writing the monster memory to a file get sources for nethack/omega, look for any really good ideas, also check to see how the implement Mac compatibility, portability, protection, and other general concepts treasure.c has an arrow and a bolt out of order (arrow in the rings, and bolt in the amulets) secret doors are always granite, would be nice to have secrets doors hidden in other types of rock, would make them less obvious when hightlight seams is on, also current scheme gives an advantage while searching since walls displayed as % obviously are not secret doors MAX_SIGHT is 20, but rooms can be larger than twenty across, that gives strange situation where moving one step away from a monster in a large room can cause it to disappear, either increase MAX_SIGHT to be size of largest possible room size, or else use different MAX_SIGHT values in rooms/corridors/ town level? instead of printing 'it can hit to attack and hit to attack' print 'it can hit to attack twice' in monster descriptions? - change haggling so that initial price depends on how many good bargains you have had - add key to accept price, instead of forcing player to type in price - when reach perfect haggling, should just give object to player without asking for any prompt, bad idea if someone mistypes a letter - add an option so that player can play with or without haggling, without haggling, give prices that are always, say, 30% above the minimum - add store commands to buy/sell without haggling, with price say, 20%, less/greater than asking price improve map command (see nethack), define an array of special characters, one for each type of composite wall, say, and then let end users specify the necessary graphic characters, allow for multiple character graphic sequences combat in a room should have a chance of waking up sleeping monsters, except that it would not be fair, since monsters can send breath weapons through other monsters, but the player can only attack the nearest monsters (high level?) monsters should slowly regenerate hit points, esp since the doc states that the Balrog does note, if leave level and come back, the Balrog is regenerated (sic) with full hit points every 128 turns, let monsters regenerate 1/64 of their total hit points? have several different types of Balrog, i.e. a fire breathing one, a cold breathing one, a lightning breathing one, etc. should be a chance of weapons breaking when try to dig with them? NO, it is too easy to dig with weapon by accident, shouldn't dull them unless there is some way to sharpen them which there currently isn't can get small groups of rooms which are connected to each other, but not to the rest of the rooms on the level, perhaps check for cycles in tunnel/room graph before trying to build tunnels? can not use counted commands while bashing a door, because of the paralyzation that sometimes occurs always stops a counted command allow character building, by allocation of a limited number of stat points, instead of random rerolling?? add another aux inventory slot, so that there is one for picks, and one for bows decrease mithril values, increase gem values, more expensive items in the shops, should be greater difference between prices of low level objects and high level objects, more gold/silver/copper on lower levels, selling high enchanted objects should not be so profitable (good idea here, favorite suggestion for fixing the money problem) in object_offset(), give 70/71 and 75/76 different codes, shift by 5 (32) everywhere instead of 6 (64), reduce size of object_ident[] from 7*64 to 9*32, objects 71 must all have 2 added to subval so that they start at 96, objects 76 must all have 1 added to subval all variables (including bss) should be initialized before they are used, see the mac sources add a macro capability most case statements should use table or if/else instead, table are much faster, both give much smaller code if have one unidentified object, and sell it to a store, and it gets identified, and you happen to have some similar store items, you will get a 'combining' message, even though no combining is really taking place, perhaps adding an extra parameter to identify which indicates whether the item will remain in inventory after ident, if it does not remain, then should not give combining message if there is only one of them many of the constants in constant.h should really be enums instead, this would make the game more maintainable some fields of treasure_type are const and could be deleted missile weapons should be made more useful, make them stackable after identified if they are identical, increase the benefit of using proper bow/arrow combo, increase +todam, +tohit more than now, perhaps give an advantage here to fighters/paladins/rangers/rogues somehow, don't decrease ptohit so much in inven_throw() (currently reduced by distance) should recall info be set in breath() for other monsters? finish monster compiler, write defs for all monsters should be able to increase digging plusses for weapons?? should be able to increase ring plusses?? this would seriously unbalance the game if allowed in the store bargain code, separate the sell good bargains from the purchase good bargains? this is important for owners with very high inflate values as it is easy to reach sell final value, but very difficult to reach purchase final value, change from 20 to 10 if do this change move to take a char-number i.e. '0' instead of a number, i.e. 0 put all prt_ functions into a separate file, put all movement functions in a separate file define constants for all possible tchars, number-directions, attack-types, last_line = 23, scroll flags, potion flags, etc would be nice if 10-23 were all wielded objects, i.e. move light 15 outside this range use scroll bars on the Mac version for showing the rest of the level, L/W, might be confusing since this won't scroll the whole window, only the dungeon view have multiple windows, one for inventory, one resizable/scrollable for dungeon view, etc... should eliminate need for 70/71 scrolls and 75/76 potions replace hex flag fields in treasure with constants should not get message "something rolls under feet" when step on a loose rock /* Hid Obj*/ trap?, also should not get this message when cast create food some people prefer to have these messages though %%%%%%%%%%%%% ideas from Bron Campbell Nelson bron%bronze.wpd.sgi.com@sgi.sgi.com potion of boldness should have duration, i.e. should be safe from fear for a little while after quaffing boldness potion (also heroism/super-heroism) the current length values seem a little long, perhaps just improve the characters resistance to fear? warriors too hard, give them more hitpoints?, lower base-to-hit of other classes?, fix warrior so can withstand one AMHD poison breath attack? boots of speed are too hard to find, 1/7000 is ring of speed, 1/14000+ is boots of speed, other evidence suggests that boots are about 10 times as rare as rings items needed for win: see invisible, free action, resist fire, speed, if add black market, don't make it too easy to get these items black market suggestions: staff of teleportation 20000, staff of speed 100000, mushroom of restoring 20000, and perhaps some powerful archery items heavy armor is useless, does not protect against spells/breate, and reduces from to-hit, reduce penalty for characters with high STR? new shop: enchantorium, where enchantments can be purchased for a high price, price proportional to how many enchants already there (i.e. enchanting a +9 item costs a fabulous amount, but enchanting a +0 item costs a little more than one enchant armor/weapon scroll), allow enchant to any value, i.e. AC/digging for HA/DF, digging for picks/shovels/etc, etc... less reasonble suggestions follow... too many weapon types, the variety is useless have armor protect by subtracting ac/10 (sic) instead of reducing by % speed is too important, need smaller time quanta race/class adjustments should be more meaningful, give races/classes max stat values which are not 18/100 add an autosave option add more up stairways? currently there are only randint(2) per level, perhaps guarantee that there will be at least 2 warriors should automatically recognize ego weapons dispel evil/undead are nearly worthless since they do not do much damage for their mana cost, change dispel_creature from mon_take_hit (i, randint(damage)) to mon_take_hit (i, damage) rune of protection is too powerful, reduce OBJ_RUNE_PROT to 800, maybe 1000, if make this change, should make the spell somewhat easier to cast, say 50% for a level 33 priest DJG: this makes them much less useful against the Balrog Balrog should not cast cause serious wounds as it does less damage than a normal attack, should not cast slow/paralyze since the player almost certainly will have some form of free action %%%%%%%%%%%%%%%%%%%%%%%%% reincarnate, and lose 1/2 exp? give enchant scrolls (or perhaps just *enchant*) a small probability of creating ego weapons give enchant scrolls a small probability of destroying ego enchantments if they fail to increase pluses make the number of hits per round probabilistic, i.e. instead of getting 1/2/3/4 hits per round, gives weapons 2.4 hits per round etc, to smoothen the curve perhaps add option to order monsters differently? give list of all monsters of that type, and then recall all if type 0, else only recall the one indicated by the number typed in change ident_char() in help.c have all top level action functions (aim, move, throw, inven_command, etc.) return true if took a turn, otherwise false add command to show number of turns played, time spent playing, date character started, perhaps even a calendar to give game date '1037 in the Third Age' enter_store in store2.c calls draw_cave when exiting the store, it should save the current screen contents away in memory and then restore from that saved screen if type control-C while resting, sometimes the counter is not cleared, happens often when count less than 10, to fix, should move all I/O code out of signal handler, it should just set a flag and return should examine_book(), scrolls(), and spells/prayers work when hallucinating? change player attributes to counters, things like sustain_stat, etc. this would greatly simplify calc_bonuses() should not be able to stun creates which do not move, and creatures which have no brains los code used to determine if monsters are visible but not for objects, this leads to strange situations, when room lights up, one can see all objects in the room, but must enter the room before can see then monsters have the monster generator make a table of undead monster indexes, to simplify summon_undead() add some unique levels to make it more interesting, mazes, etc. add a metric option add diagonal corridors??? add a storage rental shop, so players can save objects until they need them, but must pay for the priviledge, and have to go back to level 0 to retrieve the objects create a safe haven for the player, where hp regen faster, poison/disease cure faster, and player must be in to win add amulet of poison resistance, make it a high level item, people would have to take off amulet of the magi to wear it add another set of gain stat potions, at about 1550 feet, to encourage people to go deeper in search of them add a bank for saving/borrowing money (I don't like this), would rather make money less plentiful, perhaps make magic items less profitable to sell? possible AD&D enhancements mages can't wear armor and cast at the same time, stealth decreases when wearing armor (for thieves), priests can't use edged weapons, spell casting takes time (more than one turn for high level spells?), ranger attack bonuses, paladin's laying on hands and wealth limits give females better dexterity, and/or better spell casting ability, and/or more stealth Orcs should always appear in groups? possible balancing enhancements characters have max stat of 18/50+ initial race/class mod, for example, human mage has max str of 18/50 - 5 = 18. increase warrior HP so that a warrior can withstand one breath of any type frlom any dragon dex is very important, so everybody should have a chance of getting high dex values add option to find code so that it can optionally stop before lighting up or entering a room add otpion to find code so that will enter corridor intersections Change key-dispatch table in dungeon.c back to ORIGINAL mode. put shell_out code in OS dependent files, unix.c/msdos.c/etc. save all levels, problems with the sheer size of doing this, 10K * 50 levels is 500K total change stats to straight 1-40 range replace sets.c with an array ~110*16 with a flag for each type of damage faster and smaller than current scheme add option to loc_symbol so that it can optionally print char to screen, most loc_symbol calls feed directly to print() the look code uses a different algorithm from the los code, is recursive, hard to understand, has 3 gotos, I would prefer code more like los using the shading ideas of jnh lose_dex is never called, well, we'd better fix that! for characters with low dex, should have slight chance of dropping weapon, maybe less for fighters, more for mages and priests, should also trip occassionally when running acid attacks should lower charisma? the first nasty invisible monster is the Banshee at 1200 feet, so need to have see invisible items start appearing at about this time, the current balance seems OK to me though black mold, and shimmering mold have 00000080 CMOVE flag set which has no effect boots of great mass can be identified by checking the weight display, should eliminate them and replace with some other type of cursed boots suggestion: boots of two left feet, (- to dexterity) add another field to monster_type, treasurep, cloned/multiplyed monsters should not have treasure, but if they pick up an object, then again let them carry treasure change randnor from table lookup to 8d99, save 512 bytes for table remove ASCII dependencies many places assume that a-z are consecutive, i.e. 'a'+25 = 'z' the hallucination code assumes ascii - randint(95)+31 (misc1.c) eliminate sscanf calls in ms_misc.c and wizard.c allow numbers instead of letters in menus, i.e. spell lists, inventory/equip lists don't use num-lock for tunneling in PC version, this is a locking key characters accumulate too much cash, perhaps do this: change OBJ_TOWN_LEVEL from 7 to 17, and change place_gold() in misc2.c 293c293,294 < i = ((randint(dun_level+2)+2)/2.0) - 1; --- > /* NF: Change randint multiplier from (r(d+2)+2)/2 to (r(d+2)+4)/3 */ > i = ((randint(dun_level+2)+4)/3.0) - 1; the fixes above (decrease mithril values ...) are preferable show time elapsed playing, date character started, and number of turns elapsed have option to put inventory/equipment list on one screen set a timer, and if the game has been idle for 15 minutes, gracefully save and exit? new monster suggestions by berman-andrew@yale, because there are no medium difficult mosnters before level 40... {"Electric Golem", 0x00020002, 0x00080004, 0x1080, 100, 380, 12, 85, 0, 'g', "70d8", "8 1 1d24|8 1 1d24", 35} {"Queen Harpy", 0x37120012, 0x00008208, 0x2036, 100, 1200, 20, 80, 2, 'h', "46d8", "1 3 2d6|1 3 2d6|1 2 2d12|3 7 0d0", 35} new monster suggestions by Don Dodson Nether Lich: invisible, phases through walls, similar to Emperor Lich in other respects Archer: fires arrows that do normal damage, or poison, or reduce stat Wizard: Like a sorceror but more powerful. Casts fireballs, summons all sorts of nasties, blindness, and hold person. Very high saving throw and resistant for fire/frost. balls should affect player if inside radius, unfortunately, this is not really such a good idea, since the player is often forced to cast to the next space, would be OK if the player can specify any point for the target of the spell when resting, a player should have a chance of not waking up when a monster enters a room add wizard command that would create new MORIA_HOU file, since there already is a default def for it, otherwise, make days array bss for HA weapons, p1 is used for both str increase, and sustain stat rewrite my own sprintf routine that just takes strings %s and integers %d and nothing else, may be faster/smaller than the library version, or perhaps have a routine which cats 3 strings together, or 2 strings and an int age characters before killing them of Ripe-Old-Age these commands which take a dir should not work when confused, closeobject, jamdoor, openobject monsters need a 'not carry large object' flag in CMOVE, have all chests (type 2), polearms (type 22) and staffs (type 55) be large objects, these should be rerolled if they occur when only small objects allowed, chests should have this bit set, also small creatures should have it set: kobolds, mummified kobolds, greedy little gnomes, scruffy-looking hobbits. trap names are vague, have two names for each trap, a simple search discloses current vague name, setting it off, or a find/identify trap gives the long name allow option of making aux files either hard coded paths, or paths relative to the executables directory, could then make the aux files relative, put exe file in same directory as aux files, and start up program with shell script that cds to aux file direcotry, this makes it easy to keep multiply moria versions around allow rerolling after choose race/class still too slow on i/o, perhaps rewrite to avoid refresh() calls? perhaps use only motion optimization stuff? should we call m_name if spell only applies to visible creatures? when moving on objects, say what character moved onto (like rogue) for throw command, ask for direction first (like rogue) should be able to enchant to-hit to-dam of gauntlets of slaying? likewise, enchant toac of HA swords, etc. either should allow enchant of HA sword toac, or else disenchanter bats should not be allowed to reduce it fix save files to include obj desc, then only need one random number generator which can use table program give rogues detect treasure and detect objects, also give them a chance to steal objects from monsters modify 'x' command to show monster hitpoints replace magic numbers with constants name objects if use did not identify them when creature steals and then dies, the stolen item should appear, unless creature has teleported away in the meantime always add exp to current and max, instead of just increasing max when current exceeds it, this would make attacking undead creatures a little more profitable since you are guaranteed a net gain of exp if you kill it, even if it drains a lot of EXP from you allow chests to hold items have a global variable, savefile field to keep track of the number of times a character has been resurrected should not be able to use a two-handed weapon (two-handed sword, pole arm, bow, crossbow, flail, etc.) at same time as wearing a shield should be able to also choose to wield two weapons, but with a penalty of some sort, probably lowered AC can't cast in any direction, should be able to, should also be able to cast down at feet (5), should be able to cast area affect spells (balls) at any point, so that the burst will affect any desired area Long term stuff, enhancement suggestions: give player something to do with money, i.e. 1Million gp for HA +10 +10 sword 'flavor' the levels, dragons on one level, undead on another, etc. what's been discovered list commands not close enough to rogue style fixed item lettering in inventory, in-line/cmd-line options? command line option to print out times open Y destroy command, allow destroy from equipment list let o, c, D commands automatically pick direction when they can give rogue's a chance to steal, e.g. let monsters carry items that they pick up, if rogue fails, then monster gets a free hit, otherwise monster stays asleep, with a small chance of monster waking up give magic users a chance at pre identifying scrolls could use a help system, like VMS version have multiple character parties, note that almost everything character dependent is stored in the py structure already could reduce the size of the types.h file (and other source files too) if eliminate reduce type specifiers, i.e. int32u cmove;\n int32u spells; could be int32u cmove,\n spells; add color, i.e. red dragons show up as a red 'D', etc an inn on the town level, in which you must pay to stay, could be used by those who need to wait to get back into a store, or who want to wait until a store's inventory changes when look at monsters, give monster state in addition to monster name, i.e. "You see a sleeping ancient red dragon." add code to the get_dir() function so that one can optionally specific a hex instead of a direction, i.e. if you enter '.', then program goes into a cursor positioning mode, allowing you to move the cursor to the spot you want to specify don't like the player_exp values, the increase is not very even, especially in the upper levels cloak of protection is misleading, it has no special features need documentation on what each spell/prayer/staff/etc does, this is needed for priestly spells in particular, since these are non obvious also needed for special objects, such as crown of magi eating elvish waybread for curing can cause a character to become bloated and start moving slower, either decrease food value of ew to 5000, or increase player food limit to 17500, or combination of both, or perhaps change the you are full message, maybe have another message at 7500?, or maybe make elvish waybread immune to the slowing effect monsters should be more intelligent, should know about corridors so that they don't get stuck in dead ends, or continually retrace their movement RNG for Moria should have a table shuffle, see Knuth don't update store inventories across save, unless the save file is at least, say, an hour old when monster appears, print its name, may need some work to work reasonably with detect spells Features: hero/superhero do not subtract hit points when effect wears off WOR scroll can save you with minus hit points!! detect monster does not detect invisible monsters (normally) can hit monsters in walls, but can not cast at them can not enchant something with negative numbers (i.e. cursed items) how does armor protect against breath/gas? it doesn't!!! missing amulets: strength, constitution, intelligence, dexterity missing rings: gain wisdom, gain charisma note that missing rings/amulets are disjoint missing detect monster potion (feature!) missing blank scrolls (feature!) missing staff genocide (feature!) missing staff mass_genocide (feature!) D&D Inconsistencies, most of these should not be fixed since that would unbalance the game: priests should not need light for prayers magic missile should do 1d4+1 per level detect invisible should last 5 rounds, instead of 1 stinking cloud should be renamed cloudkill fireball does 1d6 per level, should destroy all paper/wood and melt metal lightning does 1d6 per level hold monster 1 round per level of caster phase door by touching a wall, and end up on other side of the wall light spells should be mobile heroism should not work when over level 11, superheroism should not work when over level 14 rings can not be used cummulatively, rings or prot have no effect if wearing armor Flame Tongue, +3 versus cold creatures and avian, +4 vs undead Holy Avenger, +50% on all saving throws moria-5.6.debian.1/unix/0000755000175000017500000000000011074760026013151 5ustar pjbpjbmoria-5.6.debian.1/unix/Makefile.unix0000644000175000017500000001045211074725455015604 0ustar pjbpjb# BINDIR is the directory where the moria binary while be put # LIBDIR is where the other files (score, news, hours) will be put # LIBDIR must be the same directory defined in config.h # OWNER is who you want the game to be chown to. # GROUP is who you wnat the game to be chgrp to. BINDIR = /home/dgrabiner/moria-5.6 LIBDIR = /home/dgrabiner/moria-5.6/files OWNER = dgrabiner GROUP = dgrabiner # For testing and debugging the program, it is best to use this line. # CFLAGS = -g # For playing the game, you may want to use this line CFLAGS = -O # For BSD Systems CURSES = -lcurses -ltermcap # For SYS V Systems # CURSES = -lcurses # For XENIX, some XENIX systems may need -ltinfo # CURSES = -ltcap -ltermcap -lx # For AIX systems, compiling in the BSD world; SYS_V must not be defined in # config.h if you use this. #LFLAGS = -lbsd # Normal systems don't require anything here. LFLAGS = CC = cc SRCS = main.c misc1.c misc2.c misc3.c misc4.c store1.c files.c io.c \ create.c desc.c generate.c sets.c dungeon.c creature.c death.c \ eat.c help.c magic.c potions.c prayer.c save.c staffs.c wands.c \ scrolls.c spells.c wizard.c store2.c signals.c moria1.c moria2.c \ moria3.c moria4.c monsters.c treasure.c variable.c rnd.c recall.c \ unix.c player.c tables.c OBJS = main.o misc1.o misc2.o misc3.o misc4.o store1.o files.o io.o \ create.o desc.o generate.o sets.o dungeon.o creature.o death.o \ eat.o help.o magic.o potions.o prayer.o save.o staffs.o wands.o \ scrolls.o spells.o wizard.o store2.o signals.o moria1.o moria2.o \ moria3.o moria4.o monsters.o treasure.o variable.o rnd.o recall.o \ unix.o player.o tables.o LIBFILES = hours news origcmds.hlp owizcmds.hlp roglcmds.hlp rwizcmds.hlp \ version.hlp welcome.hlp moria : $(OBJS) $(CC) -o moria $(CFLAGS) $(OBJS) $(CURSES) $(LFLAGS) lintout : $(SRCS) lint $(SRCS) $(CURSES) > lintout lintout2 : $(SRCS) lint -bach $(SRCS) $(CURSES) > lintout TAGS : $(SRCS) ctags -x $(SRCS) > TAGS # you must define BINDIR and LIBDIR before installing # assumes that BINDIR and LIBDIR exist install: chmod 755 $(BINDIR) cp moria $(BINDIR) chmod 4711 $(BINDIR)/moria chmod 711 $(LIBDIR) (cd files; cp $(LIBFILES) $(LIBDIR)) (cd $(LIBDIR); chmod 444 $(LIBFILES)) (cd $(LIBDIR); touch scores; chmod 644 scores) chown $(OWNER) $(BINDIR)/moria chgrp $(GROUP) $(BINDIR)/moria (cd $(LIBDIR); chown $(OWNER) $(LIBFILES) scores) (cd $(LIBDIR); chgrp $(GROUP) $(LIBFILES) scores) # If you are short on disk space, or aren't interested in debugging moria. # strip $(BINDIR)/moria clean: rm -r *.o rm -i moria create.o: constant.h types.h externs.h config.h creature.o: constant.h types.h externs.h config.h death.o: constant.h types.h externs.h config.h desc.o: constant.h types.h externs.h config.h dungeon.o: constant.h types.h externs.h config.h eat.o: constant.h types.h externs.h config.h files.o: constant.h types.h externs.h config.h generate.o: constant.h types.h externs.h config.h help.o: constant.h types.h externs.h config.h io.o: constant.h types.h externs.h config.h magic.o: constant.h types.h externs.h config.h main.o: constant.h types.h externs.h config.h misc1.o: constant.h types.h externs.h config.h misc2.o: constant.h types.h externs.h config.h misc3.o: constant.h types.h externs.h config.h misc4.o: constant.h types.h externs.h config.h monsters.o: constant.h types.h config.h moria1.o: constant.h types.h externs.h config.h moria2.o: constant.h types.h externs.h config.h moria3.o: constant.h types.h externs.h config.h moria4.o: constant.h types.h externs.h config.h player.o: constant.h types.h config.h potions.o: constant.h types.h externs.h config.h prayer.o: constant.h types.h externs.h config.h recall.o: constant.h config.h types.h externs.h rnd.o: constant.h types.h save.o: constant.h types.h externs.h config.h scrolls.o: constant.h types.h externs.h config.h sets.o: constant.h config.h signals.o: constant.h types.h externs.h config.h spells.o: constant.h types.h externs.h config.h staffs.o: constant.h types.h externs.h config.h store1.o: constant.h types.h externs.h config.h store2.o: constant.h types.h externs.h config.h tables.o: constant.h types.h config.h treasure.o: constant.h types.h config.h unix.o: constant.h config.h types.h externs.h variable.o: constant.h types.h config.h wands.o: constant.h types.h externs.h config.h wizard.o: constant.h types.h externs.h config.h moria-5.6.debian.1/unix/unix.c0000644000175000017500000002151711074751155014311 0ustar pjbpjb/* unix/unix.c: UNIX dependent code. -CJS- Copyright (c) 1989-91 James E. Wilson, Christopher J. Stuart This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ /* defines NULL */ #include /* defines CTRL */ #include /* defines TRUE and FALSE */ #include #include "config.h" #include "constant.h" #include "types.h" #ifdef unix #if defined(SYS_V) && defined(lint) /* for AIX, prevent hundreds of unnecessary lint errors, must define before signal.h is included */ #define _h_IEEETRAP typedef struct { int stuff; } fpvmach; #endif #include #ifdef M_XENIX #include #include /* For various selects from TCP/IP. */ #define bzero(addr,n) memset((char *)addr, 0, n) #endif #ifndef USG #include #include #include #include #endif #ifdef __linux__ #include #include #include #endif #ifdef USG #include #if 0 /* Used to include termio.h here, but this is unnecessary because it is included in curses.h, and some systems fail when it gets included twice. */ #include #endif #include #else #include #if defined(atarist) && defined(__GNUC__) /* doesn't have */ #else #include #endif #endif /* This must be included after fcntl.h, which has a prototype for `open' on some systems. Otherwise, the `open' prototype conflicts with the `topen' declaration. */ #include "externs.h" #include #include #ifdef USG struct passwd *getpwuid(); struct passwd *getpwnam(); #endif #if defined(SYS_V) && defined(lint) struct screen { int dumb; }; #endif /* Fooling lint. Unfortunately, c defines all the TIO constants to be long, and lint expects them to be int. Also, ioctl is sometimes called with just two arguments. The following definition keeps lint happy. It may need to be reset for different systems. */ #ifdef lint #ifdef Pyramid /* Pyramid makes constants greater than 65535 into long! Gakk! -CJS- */ /*ARGSUSED*/ /*VARARGS2*/ static Ioctl(i, l, p) long l; char *p; { return 0; } #else /*ARGSUSED*/ /*VARARGS2*/ static Ioctl(i, l, p) char *p; { return 0; } #endif #define ioctl Ioctl #endif /* Provides for a timeout on input. Does a non-blocking read, consuming the data if any, and then returns 1 if data was read, zero otherwise. Porting: In systems without the select call, but with a sleep for fractional numbers of seconds, one could sleep for the time and then check for input. In systems which can only sleep for whole number of seconds, you might sleep by writing a lot of nulls to the terminal, and waiting for them to drain, or you might hack a static accumulation of times to wait. When the accumulation reaches a certain point, sleep for a second. There would need to be a way of resetting the count, with a call made for commands like run or rest. */ int check_input(microsec) int microsec; { #if defined(USG) && !defined(M_XENIX) && !defined(__linux__) int arg, result; #else struct timeval tbuf; int ch; #if defined(BSD4_3) || defined(M_XENIX) || defined(__linux__) fd_set smask; #else int smask; #endif #endif /* Return true if a read on descriptor 1 will not block. */ #if !defined(USG) || defined(M_XENIX) || defined(__linux__) tbuf.tv_sec = 0; tbuf.tv_usec = microsec; #if defined(BSD4_3) || defined(M_XENIX) || defined(__linux__) FD_ZERO(&smask); FD_SET(fileno(stdin), &smask); if (select(1, &smask, (fd_set *)0, (fd_set *)0, &tbuf) == 1) #else smask = 1; /* i.e. (1 << 0) */ if (select(1, &smask, (int *)0, (int *)0, &tbuf) == 1) #endif { ch = getch(); /* check for EOF errors here, select sometimes works even when EOF */ if (ch == -1) { eof_flag++; return 0; } return 1; } else return 0; #else /* SYS V code follows */ if (microsec != 0 && (turn & 0x7F) == 0) (void) sleep (1); /* mod 128, sleep one sec every 128 turns */ /* Can't check for input, but can do non-blocking read, so... */ /* Ugh! */ arg = 0; arg = fcntl(0, F_GETFL, arg); arg |= O_NDELAY; (void) fcntl(0, F_SETFL, arg); result = getch(); arg = 0; arg = fcntl(0, F_GETFL, arg); arg &= ~O_NDELAY; (void) fcntl(0, F_SETFL, arg); if (result == -1) return 0; else return 1; #endif } #if 0 /* This is not used, however, this should be compared against shell_out in io.c */ /* A command for the operating system. Standard library function 'system' is unsafe, as it leaves various file descriptors open. This also is very careful with signals and interrupts, and does rudimentary job control, and puts the terminal back in a standard mode. */ int system_cmd(p) char *p; { int pgrp, pid, i, mask; union wait w; extern char *getenv(); mask = sigsetmask(~0); /* No interrupts. */ restore_term(); /* Terminal in original state. */ /* Are we in the control terminal group? */ if (ioctl(0, TIOCGPGRP, (char *)&pgrp) < 0 || pgrp != getpgrp(0)) pgrp = -1; pid = fork(); if (pid < 0) { (void) sigsetmask(mask); moriaterm(); return -1; } if (pid == 0) { (void) sigsetmask(0); /* Interrupts on. */ /* Transfer control terminal. */ if (pgrp >= 0) { i = getpid(); (void) ioctl(0, TIOCSPGRP, (char *)&i); (void) setpgrp(i, i); } for(i = 2; i < 30; i++) (void) close(i); /* Close all but standard in and out.*/ (void) dup2(1, 2); /* Make standard error as standard out. */ if (p == 0 || *p == 0) { p = getenv("SHELL"); if (p) execl(p, p, 0); execl("/bin/sh", "sh", 0); } else execl("/bin/sh", "sh", "-c", p, 0); _exit(1); } /* Wait for child termination. */ for(;;) { i = wait3(&w, WUNTRACED, (struct rusage *)0); if (i == pid) { if (WIFSTOPPED(w)) { /* Stop outselves, if child stops. */ (void) kill(getpid(), SIGSTOP); /* Restore the control terminal, and restart subprocess. */ if (pgrp >= 0) (void) ioctl(0, TIOCSPGRP, (char *)&pid); (void) killpg(pid, SIGCONT); } else break; } } /* Get the control terminal back. */ if (pgrp >= 0) (void) ioctl(0, TIOCSPGRP, (char *)&pgrp); (void) sigsetmask(mask); /* Interrupts on. */ moriaterm(); /* Terminal in moria mode. */ return 0; } #endif #ifndef DEBIAN_LINUX #ifdef USG unsigned short getuid(); #else #ifndef SECURE #ifdef BSD4_3 uid_t getuid(); #else /* other BSD versions */ int getuid(); #endif #endif #endif #endif /* Find a default user name from the system. */ void user_name(buf) char *buf; { extern char *getlogin(); struct passwd *pwline; register char *p; p = getlogin(); if (p && p[0]) (void) strcpy(buf, p); else { pwline = getpwuid((int)getuid()); if (pwline) (void) strcpy(buf, pwline->pw_name); } if (!buf[0]) (void) strcpy(buf, "X"); /* Gotta have some name */ } /* expands a tilde at the beginning of a file name to a users home directory */ int tilde(file, exp) char *file, *exp; { *exp = '\0'; if (file) { if (*file == '~') { char user[128]; struct passwd *pw = NULL; int i = 0; user[0] = '\0'; file++; while (*file != '/' && i < sizeof(user)) user[i++] = *file++; user[i] = '\0'; if (i == 0) { char *login = (char *) getlogin(); if (login != NULL) (void) strcpy (user, login); else if ((pw = getpwuid(getuid())) == NULL) return 0; } if (pw == NULL && (pw = getpwnam(user)) == NULL) return 0; (void) strcpy (exp, pw->pw_dir); } (void) strcat(exp, file); return 1; } return 0; } /* undefine these so that tfopen and topen will work */ #undef fopen #undef open /* open a file just as does fopen, but allow a leading ~ to specify a home directory */ FILE *tfopen(file, mode) char *file; char *mode; { char buf[1024]; extern int errno; if (tilde(file, buf)) return (fopen(buf, mode)); errno = ENOENT; return NULL; } /* open a file just as does open, but expand a leading ~ into a home directory name */ int topen(file, flags, mode) char *file; int flags, mode; { char buf[1024]; extern int errno; if (tilde(file, buf)) return (open(buf, flags, mode)); errno = ENOENT; return -1; } #endif moria-5.6.debian.1/unix/Makefile0000644000175000017500000001245410757665645014641 0ustar pjbpjb# Edited for Debian GNU/Linux. DESTDIR = # DEBIAN NOTE: This file diverges significantly from the original Makefile # for obvious reasons. The original Makefile is Makefile.unix and should # be used on non-Linux systems. # BINDIR is the directory where the moria binary while be put # LIBDIR is where the other files (score, news, hours) will be put # LIBDIR must be the same directory defined in config.h # Edited for Debian GNU/Linux: Next 4 lines are for the FHS # Edited for Debian GNU/Linux: LIBDIR is retired # Edited for Debian GNU/Linux: ETCDIR is where the hours file is kept # Edited for Debian GNU/Linux: LIBSTATICDIR is where help files are kept # Edited for Debian GNU/Linux: LIBVARDIR is where the score file is kept # OWNER is who you want the game to be chown to. # GROUP is who you wnat the game to be chgrp to. BINDIR = $(DESTDIR)/usr/games ETCDIR = $(DESTDIR)/etc LIBSTATICDIR = $(DESTDIR)/usr/lib/games/moria LIBVARDIR = $(DESTDIR)/var/games/moria OWNER = root GROUP = games # For testing and debugging the program, it is best to use this line. # CFLAGS = -g # For playing the game, you may want to use this line CFLAGS = -O2 # Debian GNU/Linux addition ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS))) CFLAGS += -g endif # For BSD Systems # CURSES = -lcurses -ltermcap # For SYS V Systems CURSES = -lcurses # For XENIX, some XENIX systems may need -ltinfo # CURSES = -ltcap -ltermcap -lx # For AIX systems, compiling in the BSD world; SYS_V must not be defined in # config.h if you use this. #LFLAGS = -lbsd # Normal systems don't require anything here. LFLAGS = CC = cc SRCS = main.c misc1.c misc2.c misc3.c misc4.c store1.c files.c io.c \ create.c desc.c generate.c sets.c dungeon.c creature.c death.c \ eat.c help.c magic.c potions.c prayer.c save.c staffs.c wands.c \ scrolls.c spells.c wizard.c store2.c signals.c moria1.c moria2.c \ moria3.c moria4.c monsters.c treasure.c variable.c rnd.c recall.c \ unix.c player.c tables.c OBJS = main.o misc1.o misc2.o misc3.o misc4.o store1.o files.o io.o \ create.o desc.o generate.o sets.o dungeon.o creature.o death.o \ eat.o help.o magic.o potions.o prayer.o save.o staffs.o wands.o \ scrolls.o spells.o wizard.o store2.o signals.o moria1.o moria2.o \ moria3.o moria4.o monsters.o treasure.o variable.o rnd.o recall.o \ unix.o player.o tables.o LIBSTATICFILES = news origcmds.hlp owizcmds.hlp roglcmds.hlp rwizcmds.hlp \ version.hlp welcome.hlp moria : $(OBJS) $(CC) -o moria $(CFLAGS) $(OBJS) $(CURSES) $(LFLAGS) lintout : $(SRCS) lint $(SRCS) $(CURSES) > lintout lintout2 : $(SRCS) lint -bach $(SRCS) $(CURSES) > lintout TAGS : $(SRCS) ctags -x $(SRCS) > TAGS # you must define BINDIR and LIBDIR before installing # assumes that BINDIR and LIBDIR exist install: chmod 755 $(BINDIR) cp moria $(BINDIR) chown $(OWNER) $(BINDIR)/moria chgrp $(GROUP) $(BINDIR)/moria chmod 2755 $(BINDIR)/moria chmod 755 $(LIBSTATICDIR) # No longer chmod 755 $(LIBVARDIR) (cd files; cp $(LIBSTATICFILES) $(LIBSTATICDIR)) (cd $(LIBSTATICDIR); chmod 444 $(LIBSTATICFILES)) # No longer (cd $(LIBVARDIR); touch scores; chmod 664 scores) # No longer (cd $(LIBVARDIR); chown $(OWNER) . scores; chgrp $(GROUP) . scores) (cd files; cp hours $(ETCDIR)/moria-hours) chmod 644 $(ETCDIR)/moria-hours (cd $(LIBSTATICDIR); chown $(OWNER) $(LIBSTATICFILES)) (cd $(LIBSTATICDIR); chgrp $(GROUP) $(LIBSTATICFILES)) # If you are short on disk space, or aren't interested in debugging moria. # This is handled by dh_strip, so let's not override its' decision. # strip $(BINDIR)/moria clean: rm -r *.o rm -f moria create.o: constant.h types.h externs.h config.h creature.o: constant.h types.h externs.h config.h death.o: constant.h types.h externs.h config.h desc.o: constant.h types.h externs.h config.h dungeon.o: constant.h types.h externs.h config.h eat.o: constant.h types.h externs.h config.h files.o: constant.h types.h externs.h config.h generate.o: constant.h types.h externs.h config.h help.o: constant.h types.h externs.h config.h io.o: constant.h types.h externs.h config.h magic.o: constant.h types.h externs.h config.h main.o: constant.h types.h externs.h config.h misc1.o: constant.h types.h externs.h config.h misc2.o: constant.h types.h externs.h config.h misc3.o: constant.h types.h externs.h config.h misc4.o: constant.h types.h externs.h config.h monsters.o: constant.h types.h config.h moria1.o: constant.h types.h externs.h config.h moria2.o: constant.h types.h externs.h config.h moria3.o: constant.h types.h externs.h config.h moria4.o: constant.h types.h externs.h config.h player.o: constant.h types.h config.h potions.o: constant.h types.h externs.h config.h prayer.o: constant.h types.h externs.h config.h recall.o: constant.h config.h types.h externs.h rnd.o: constant.h types.h save.o: constant.h types.h externs.h config.h scrolls.o: constant.h types.h externs.h config.h sets.o: constant.h config.h signals.o: constant.h types.h externs.h config.h spells.o: constant.h types.h externs.h config.h staffs.o: constant.h types.h externs.h config.h store1.o: constant.h types.h externs.h config.h store2.o: constant.h types.h externs.h config.h tables.o: constant.h types.h config.h treasure.o: constant.h types.h config.h unix.o: constant.h config.h types.h externs.h variable.o: constant.h types.h config.h wands.o: constant.h types.h externs.h config.h wizard.o: constant.h types.h externs.h config.h moria-5.6.debian.1/ibmpc/0000755000175000017500000000000011074757452013271 5ustar pjbpjbmoria-5.6.debian.1/ibmpc/ms_ansi.h0000644000175000017500000000531511074756221015070 0ustar pjbpjb/* ibmpc/ms_ansi.h: ANSI definitions for MSDOS Copyright (c) 1989-94 James E. Wilson, Don Kneller This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ /* To allow the choice between PCcurses (which may not work on all machines) * and ANSI (which should work on all machines), indirect the output routines * through pointers and adjust the pointers to the correct routines at * initialization time. */ #ifdef LINT_ARGS int (*output_addch)(int); int (*output_mvaddstr)(int, int, char *); int (*output_mvprintw)(int, int, char *, ...); int (*output_move)(int, int); int (*output_endwin)(void); int (*output_clrtobot)(void); int (*output_clrtoeol)(void); int (*output_mvaddch)(int, int, char); int (*output_initscr)(void); int (*output_refresh)(void); int (*output_clear)(void); int (*output_nocrmode)(void); int (*output_crmode)(void); int (*output_nonl)(void); int (*output_nl)(void); int (*output_noecho)(void); int (*output_echo)(void); int ansi_prep (int, int, int); #else extern int (*output_addch)(); extern int (*output_mvaddstr)(); extern int (*output_mvprintw)(); extern int (*output_move)(); extern int (*output_endwin)(); extern int (*output_clrtobot)(); extern int (*output_clrtoeol)(); extern int (*output_mvaddch)(); extern int (*output_initscr)(); extern int (*output_refresh)(); extern int (*output_clear)(); extern int (*output_nocrmode)(); extern int (*output_crmode)(); extern int (*output_nonl)(); extern int (*output_nl)(); extern int (*output_noecho)(); extern int (*output_echo)(); extern int ansi_prep(); #endif extern int ansi; #define addch (*output_addch) #define mvaddstr (*output_mvaddstr) #define mvprintw (*output_mvprintw) #undef move /* from curses.h */ #define move (*output_move) #define endwin (*output_endwin) #define clrtobot (*output_clrtobot) #define clrtoeol (*output_clrtoeol) #define mvaddch (*output_mvaddch) #define initscr (*output_initscr) #define refresh (*output_refresh) #define clear (*output_clear) #define nocrmode (*output_nocrmode) #define crmode (*output_crmode) #define nonl (*output_nonl) #define nl (*output_nl) #define noecho (*output_noecho) #define echo (*output_echo) moria-5.6.debian.1/ibmpc/make/0000755000175000017500000000000005603152201014164 5ustar pjbpjbmoria-5.6.debian.1/ibmpc/make/makefile.src0000644000175000017500000000233305603152201016453 0ustar pjbpjbCFLAG = $(FLAG) INC = \ config.h\ constant.h\ externs.h\ types.h .c.$(OBJ): cl -c $(CFLAG) -Fo$*.$(OBJ) $*.c > $*.$(REDIR) ..\ccthru $* $(OBJ) create.$(OBJ): create.c $(INC) creature.$(OBJ): creature.c $(INC) death.$(OBJ): death.c $(INC) desc.$(OBJ): desc.c $(INC) dungeon.$(OBJ): dungeon.c $(INC) eat.$(OBJ): eat.c $(INC) files.$(OBJ): files.c $(INC) generate.$(OBJ): generate.c $(INC) help.$(OBJ): help.c $(INC) io.$(OBJ): io.c $(INC) magic.$(OBJ): magic.c $(INC) main.$(OBJ): main.c $(INC) misc1.$(OBJ): misc1.c $(INC) misc2.$(OBJ): misc2.c $(INC) monsters.$(OBJ): monsters.c $(INC) moria1.$(OBJ): moria1.c $(INC) moria2.$(OBJ): moria2.c $(INC) potions.$(OBJ): potions.c $(INC) prayer.$(OBJ): prayer.c $(INC) recall.$(OBJ): recall.c $(INC) rnd.$(OBJ): rnd.c $(INC) save.$(OBJ): save.c $(INC) scrolls.$(OBJ): scrolls.c $(INC) sets.$(OBJ): sets.c $(INC) signals.$(OBJ): signals.c $(INC) spells.$(OBJ): spells.c $(INC) staffs.$(OBJ): staffs.c $(INC) store1.$(OBJ): store1.c $(INC) store2.$(OBJ): store2.c $(INC) treasure.$(OBJ): treasure.c $(INC) undef.$(OBJ): undef.c $(INC) variable.$(OBJ): variable.c $(INC) wands.$(OBJ): wands.c $(INC) wizard.$(OBJ): wizard.c $(INC) moria-5.6.debian.1/ibmpc/make/makefile.top0000644000175000017500000000261405603152201016470 0ustar pjbpjbMODEL = L OP = M REDIR = w$(OP) OPFLAG = -DMSDOS=1 -DPC_CURSES=1 -DANSI=1 OBJ = o$(OP) FLAG = -A$(MODEL) -Zp -W3 -Os -Gs -Gt32 -I.. $(OPFLAG) CFLAG = $(FLAG) LFLAG = /STACK:16383 /E $(MODEL)curses SRC1 = \ ibmpc\ms_ansi.c\ ibmpc\ms_misc.c\ misc\flock.c\ misc\funckeys.c\ misc\nomacio.c\ source\create.c\ source\creature.c\ source\death.c\ source\desc.c\ source\dungeon.c SRC2 = \ source\eat.c\ source\files.c\ source\generate.c\ source\help.c\ source\io.c\ source\magic.c\ source\main.c\ source\misc1.c\ source\misc2.c\ source\monsters.c SRC3 = \ source\moria1.c\ source\moria2.c\ source\potions.c\ source\prayer.c\ source\recall.c\ source\rnd.c\ source\save.c\ source\scrolls.c\ source\sets.c\ source\signals.c SRC4 = \ source\spells.c\ source\staffs.c\ source\store1.c\ source\store2.c\ source\treasure.c\ source\undef.c\ source\variable.c\ source\wands.c\ source\wizard.c tags: $(SRC1) $(SRC2) $(SRC3) $(SRC4) ctags -o sgat ibmpc\*.c misc\*.c source\*.c sort -u sgat > tags rm -f sgat all: cd ibmpc make MODEL=$(MODEL) OP=$(OP) OBJ=$(OBJ) REDIR=$(REDIR) \ FLAG="$(FLAG)" ibmpc.mak cd ..\misc make MODEL=$(MODEL) OP=$(OP) OBJ=$(OBJ) REDIR=$(REDIR) \ FLAG="$(FLAG)" misc.mak cd ..\source make MODEL=$(MODEL) OP=$(OP) OBJ=$(OBJ) REDIR=$(REDIR) \ FLAG="$(FLAG)" source.mak cd ..\$(OBJ) cl $(CFLAG) -Feumoria.exe *.$(OBJ) /link $(LFLAG); cd .. moria-5.6.debian.1/ibmpc/make/ccthru.bat0000644000175000017500000000011605603152201016142 0ustar pjbpjb@echo off touch %1.%2 > nul: copy %1.%2 ..\%2 > nul: touch ..\%2\%1.%2 > nul: moria-5.6.debian.1/ibmpc/make/makefile.ibm0000644000175000017500000000027105603152202016433 0ustar pjbpjbCFLAG = $(FLAG) INC = ms_ansi.h .c.$(OBJ): cl -c $(CFLAG) -Fo$*.$(OBJ) $*.c > $*.$(REDIR) ..\ccthru $* $(OBJ) ms_ansi.$(OBJ): ms_ansi.c $(INC) ms_misc.$(OBJ): ms_misc.c $(INC) moria-5.6.debian.1/ibmpc/ERRORS0000644000175000017500000000025205603152200014204 0ustar pjbpjbthe two files Makefile and Makefile.XNX are obsolete, and need to be updated document the -DLINT_ARGS option for prototypes someplace fix up the new makefiles in make/ moria-5.6.debian.1/ibmpc/umoria.prj0000644000175000017500000000041505603152201015260 0ustar pjbpjbCREATE CREATURE DEATH DESC DUNGEON EAT FILES GENERATE HELP TCIO MAGIC MAIN MISC1 MISC2 MISC3 MISC4 MONSTERS MORIA1 MORIA2 MORIA3 MORIA4 MS_MISC PLAYER POTIONS PRAYER RECALL RND SAVE SCROLLS SETS SIGNALS SPELLS STAFFS STORE1 STORE2 TABLES TREASURE VARIABLE WANDS WIZARD moria-5.6.debian.1/ibmpc/ms_ansi.c0000644000175000017500000001544011074756221015063 0ustar pjbpjb/* ibmpc/ms_ansi.c: a set of routines to provide either PCcurses or ANSI output Copyright (c) 1989-94 James E. Wilson, Don Kneller This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include #include #if defined(MSDOS) && defined(ANSI) #ifdef LINT_ARGS static int curses_move(int, int); static char *getent(char *,char * *,int ); static void initansistr(void); static int ansi_initscr(void); static int ansi_endwin(void); static int ansi_addch(int ); static int ansi_mvaddstr(int ,int ,char *); static int ansi_mvprintw(int ,int ,char *,int ,int ,int ,int ); static int ansi_move(int ,int ); static int ansi_move_tgoto(int ,int ); static int ansi_clrtobot(void); static int ansi_clrtoeol(void); static int ansi_mvaddch(int ,int ,char ); static int ansi_clear(void); static int ansi_refresh(void); static int ansi_noop(void); int ansi_prep(int ,int, int); #else static int ansi_addch(), ansi_mvaddstr(), ansi_mvprintw(), ansi_move(), ansi_move_tgoto(), ansi_clrtobot(), ansi_clrtoeol(), ansi_mvaddch(), ansi_endwin(), ansi_refresh(), ansi_clear(), ansi_noop(), ansi_initscr(); int ansi_prep(); #endif extern char *tgetstr(); extern char *getenv(); extern char *tgoto(); /* Must supply a functional form of the PCcurses "move" routine */ static int curses_move(y, x) int y, x; { return wmove(stdscr, y, x); } /* Default is for curses to be used */ int (*output_addch)() = addch; int (*output_mvaddstr)() = mvaddstr; int (*output_mvprintw)() = mvprintw; int (*output_move)() = curses_move; int (*output_endwin)() = endwin; int (*output_clrtobot)() = clrtobot; int (*output_clrtoeol)() = clrtoeol; int (*output_mvaddch)() = mvaddch; int (*output_initscr)() = initscr; int (*output_refresh)() = refresh; int (*output_clear)() = clear; int (*output_nocrmode)() = nocrmode; int (*output_crmode)() = crmode; int (*output_nonl)() = nonl; int (*output_nl)() = nl; int (*output_noecho)() = noecho; int (*output_echo)() = echo; int ansi; int LI; #define LEFTFIELD -10; #define NEED 1 static int moveopt = 1; static char *CE, *CL, *CM, *DO, *LE, *ND, *TE, *TI, *UP; static int currow = 0; static int curcol = LEFTFIELD; static char * getent(str, tbufp, need) char *str, **tbufp; int need; { char *value; if ((value = tgetstr(str, tbufp)) == NULL && need == NEED) error("termcap: Moria needs %s\n", str); return value; } static void initansistr() { static char tbuf[512]; char temp[1024], *tbufp, *term; if ((term = getenv("TERM")) == NULL) term = "ibmpc-mono"; if (tgetent(temp, term) < 1) error("Unknown terminal type: %s.", term); tbufp = tbuf; LE = getent("le", &tbufp, NEED); CE = getent("ce", &tbufp, NEED); CL = getent("cl", &tbufp, NEED); CM = getent("cm", &tbufp, NEED); ND = getent("nd", &tbufp, NEED); TE = getent("te", &tbufp, !NEED); TI = getent("ti", &tbufp, !NEED); UP = getent("up", &tbufp, NEED); DO = getent("do", &tbufp, NEED); LI = tgetnum("li"); if (LI <= 0) LI = 24; } ansi_prep(check_ansi, domoveopt, truetgoto) int check_ansi; int domoveopt; int truetgoto; { moveopt = domoveopt; /* Check for ANSI.SYS */ if (check_ansi) { /* Clear the input queue */ while (kbhit()) (void) getch(); /* Send out the DSR string */ fputs("\033[6n", stdout); fflush(stdout); /* Is there anything in the input? If so ANSI responded. */ if (kbhit()) { while (kbhit()) (void) getch(); } else { putchar('\n'); error("ANSI.SYS not installed! See MORIA.DOC for details!\n"); } } /* get the ANSI strings */ initansistr(); /* change function pointers to ANSI versions */ output_addch = ansi_addch; output_mvaddstr = ansi_mvaddstr; output_mvprintw = ansi_mvprintw; if (truetgoto) output_move = ansi_move_tgoto; else output_move = ansi_move; output_clrtobot = ansi_clrtobot; output_clrtoeol = ansi_clrtoeol; output_mvaddch = ansi_mvaddch; output_refresh = ansi_refresh; output_clear = ansi_clear; output_initscr = ansi_initscr; output_endwin = ansi_endwin; output_nocrmode = output_crmode = output_nonl = output_nl = output_noecho = output_echo = ansi_noop; ansi = 1; } static int ansi_initscr() { if (TI != NULL) fputs(TI, stdout); return OK; } static int ansi_endwin() { if (TI != NULL) fputs(TE, stdout); return OK; } static int ansi_addch(ch) int ch; { putc(ch, stdout); curcol++; return OK; } static int ansi_mvaddstr(row, col, str) int row, col; char *str; { (void) ansi_move(row, col); fputs(str, stdout); curcol = LEFTFIELD; return OK; } static int ansi_mvprintw(row, col, fmt, a1, a2, a3, a4) int row, col; char *fmt; int a1, a2, a3, a4; /* large enough for %c%s%c of files.c ! */ { (void) ansi_move(row, col); fprintf(stdout, fmt, a1, a2, a3, a4); curcol = LEFTFIELD; return OK; } #define abs(x) ((x) < 0 ? -(x) : (x)) /* For a bit more speed, don't use tgoto() from termcap */ static int ansi_move(row, col) int row, col; { if (moveopt && abs(currow - row) < 3 && abs(curcol - col) < 3) { while (row > currow) fputs(DO, stdout), currow++; while (row < currow) fputs(UP, stdout), currow--; while (col > curcol) fputs(ND, stdout), curcol++; while (col < curcol) fputs(LE, stdout), curcol--; } else fprintf(stdout, "\033[%d;%dH\0__cursor motion__", row+1,col+1); currow = row; curcol = col; return OK; } /* Use tgoto (which is rather slow) */ static int ansi_move_tgoto(row, col) int row, col; { if (moveopt && abs(currow - row) < 3 && abs(curcol - col) < 3) { while (row > currow) fputs(DO, stdout), currow++; while (row < currow) fputs(UP, stdout), currow--; while (col > curcol) fputs(ND, stdout), curcol++; while (col < curcol) fputs(LE, stdout), curcol--; } else { fputs(tgoto(CM, col, row), stdout); } currow = row; curcol = col; return OK; } static int ansi_clrtobot() { ansi_clrtoeol(); ansi_move(++currow, 0); ansi_clrtoeol(); for (; currow <= LI; currow++) { fputs(DO, stdout); ansi_clrtoeol(); } curcol = LEFTFIELD; return OK; } static int ansi_clrtoeol() { fputs(CE, stdout); return OK; } static int ansi_mvaddch(row, col, ch) int row, col; char ch; { ansi_move(row, col); putchar(ch); curcol++; return OK; } static int ansi_clear() { fputs(CL, stdout); return OK; } static int ansi_refresh() { fflush(stdout); return OK; } static int ansi_noop() { return OK; } #endif moria-5.6.debian.1/ibmpc/Makefile.tc0000644000175000017500000000122605613576550015337 0ustar pjbpjbFLAGS = -1 -c -w- DEFS = -DUSG -DMSDOS CC = \tc\bin\tcc PROGRAM = moria.exe LINKER = \tc\bin\tlink OBJS = create.obj creature.obj death.obj desc.obj dungeon.obj \ eat.obj files.obj generate.obj help.obj io.obj rnd.obj \ magic.obj main.obj misc1.obj misc2.obj misc3.obj misc4.obj \ monsters.obj moria1.obj moria2.obj moria3.obj moria4.obj \ ms_ansi.obj ms_misc.obj player.obj potions.obj \ prayer.obj save.obj scrolls.obj sets.obj signals.obj \ spells.obj staffs.obj store1.obj store2.obj treasure.obj \ variable.obj wands.obj wizard.obj .c.obj: $(CC) $(FLAGS) $(DEFS) $*.c $(PROGRAM): $(OBJS) $(LINKER) $(OBJS), $(PROGRAM),, moria-5.6.debian.1/ibmpc/README0000644000175000017500000000336405603152200014134 0ustar pjbpjb To compile this program, you need a copy of PC-Curses, a screen management package. Sources for this are distributed separately, since most people who need it already have a copy. Or, if you have Turbo C, you can use the tcio.c file instead of PC-Curses. ************************* CONFIG.DOC The MSDOS specific documentation file that came with PC-Moria 4.873. Much of this is out-of-date, and needs to be updated. The section describing the MORIA.CNF configuration file is still useful. MAKE.BAT, MLINK.LNK If you have MSC, you can compile the Umoria by executing this MAKE.BAT commands files, which uses MLINK.LNK to specify all of the files to be linked together to form the executable. MORIA.CNF A sample configuration file for the MSDOS version of umoria 5.x. Makefile, Makefile.XNX Obsolete Makefiles that were used for PC-Moria 4.873. May still be useful as a reference though for those who want to write their own Makefiles. TERMCAP A sample TERMCAP file which can be used by PC-Curses. make A directory containing 3 makefiles for MSC. Put the makefile.top file in the top directory (which contains the CHANGES file), put the makefile.src file in the source directory, and put the makefile.ibm in this directory. Note that each file must be renamed to makefile when it is moved. You can then build moria by running the MSC Make program in the top directory. ms_ansi.c, ms_ansi.h, ms_misc.c MSDOS specific source files for umoria 5.x. tcio.c For TC, this is an alternative io.c file. If you use this file instead of source/io.c, then you don't need PC-Curses. This should result in a smaller, faster program. turbo_c.inf Some hints on compiling Umoria with TC. umoria.prj A project file to be used when compiling Umoria with TC. moria-5.6.debian.1/ibmpc/tcio.c0000644000175000017500000002143505613576551014401 0ustar pjbpjb/* ibmpc/tcio.c: terminal I/O code for Turbo C Copyright (c) 1989-94 James E. Wilson, Eric Vaitl This software may be copied and distributed for educational, research, and not for profit purposes provided that this copyright and statement are included in all such copies. */ /* This I/O module doesn't need PCcurses. You may also need to make some changes to ms_misc.c; in particular, you need to comment out the #include of curses.h. */ #include /* malloc() */ #include #include #include /* getenv() */ #include /* putch */ #include /* spawnl() */ #include /* window(), gotoxy() */ #ifdef __TURBOC__ #include #endif /* __TURBOC__ */ #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #define MSG_LEN 73 #define LINES 25 #define COLS 80 static void *savescr; /* pointer to a saved screen */ void init_curses(void){ if((savescr=malloc(LINES*COLS*2))==NULL){ puts("Out of memory in init_curses()"); exit(1); } clrscr(); msdos_raw(); } int get_string(char *in_str,int row,int column,int slen) { register int start_col, end_col, i; char *p; int flag, aborted; aborted = FALSE; flag = FALSE; gotoxy(column+1,row+1); for (i = slen; i > 0; i--) putch(' '); gotoxy(column+1,row+1); start_col = column; end_col = column + slen - 1; if (end_col > 79) { slen = 80 - column; end_col = 79; } p = in_str; do { i = inkey(); switch(i) { case ESCAPE: aborted = TRUE; break; case CTRL('J'): case CTRL('M'): flag = TRUE; break; case DELETE: case CTRL('H'): if (column > start_col) { column--; put_buffer(" ", row, column); move_cursor(row, column); *--p = '\0'; } break; default: if (!isprint(i) || column > end_col) bell(); else { gotoxy(column+1,row+1); putch((char) i); *p++ = i; column++; } break; } } while ((!flag) && (!aborted)); if (aborted) return(FALSE); /* Remove trailing blanks */ while (p > in_str && p[-1] == ' ') p--; *p = '\0'; return(TRUE); } void put_buffer(char *out_str,int row,int col){ vtype tmp_str; if (col>79) col=79; strncpy(tmp_str,out_str,79-col); tmp_str[79-col]='\0'; gotoxy(col+1,row+1); cputs(tmp_str); } void put_qio(void){ /* nothing to do */ } void restore_term(void){ fflush(stdout); clear_screen(); msdos_noraw(); } void shell_out(void){ char *comspec; #ifndef __TURBOC__ char key; int val; char *str; #endif /* __TURBOC__ */ save_screen(); clear_screen(); puts("[Entering DOS shell, type exit to return to game.]"); msdos_noraw(); ignore_signals(); if((comspec=getenv("COMSPEC")) ==NULL || spawnl(P_WAIT,comspec,comspec,(char *)NULL)<0){ puts("Sorry, there seems to be a problem with shell_out()"); printf("comspec = %s\n",comspec); flush(); puts("Hit a key to continue"); while(!kbhit()) ; } restore_signals(); restore_screen(); } void save_screen(void){ gettext(1,1,COLS,LINES,savescr); } void restore_screen(void){ puttext(1,1,COLS,LINES,savescr); } void clear_screen(void){ window(1,1,COLS,LINES); /* I think later I might want to define seperate windows, so the above line is definsive code. */ clrscr(); } void clear_from(int row){ window(1,row+1,COLS,LINES); clrscr(); window(1,1,COLS,LINES); } void flush(void){ while(kbhit()) getch(); } void erase_line(int row, int col){ if(row==MSG_LINE&&msg_flag) msg_print(NULL); gotoxy(col+1,row+1); clreol(); } char inkey(void){ int i; command_count=0; while(TRUE){ i=msdos_getch(); if(i==EOF){ eof_flag++; msg_flag=FALSE; if(!character_generated||character_saved) exit_game(); disturb(1,0); if(eof_flag>100){ panic_save=1; strcpy(died_from,"(end of input: panic saved)"); if(!save_char()){ strcpy(died_from,"panic: unexpected eof"); death=TRUE; } exit_game(); } return ESCAPE; } if(i!=CTRL('R')) return (char) i; msdos_raw(); break; } return (CTRL('R')); } void print(char ch, int row, int col){ row -= panel_row_prt; col-=panel_col_prt; gotoxy(col+1,row+1); putchar((int)ch); } void move_cursor_relative(int row, int col){ row-=panel_row_prt; col-=panel_col_prt; gotoxy(col+1,row+1); } void count_msg_print(char *p){ int i; i=command_count; msg_print(p); command_count=i; } void prt(char* str_buff,int row, int col){ if (row==MSG_LINE&&msg_flag) msg_print(NULL); gotoxy(col+1,row+1); clreol(); put_buffer(str_buff,row,col); } void move_cursor(int row,int col){ gotoxy(col+1,row+1); } void msg_print(char* str_buff){ register int old_len; char in_char; if(msg_flag){ old_len=strlen(old_msg[last_msg])+1; if (old_len>MSG_LEN) old_len=MSG_LEN; put_buffer("-more-",MSG_LINE, old_len); wait_for_more=1; do{ in_char=inkey(); }while((in_char!=' ')&&(in_char!=ESCAPE)&&(in_char!='\n')&& (in_char!='\r')); wait_for_more=0; } gotoxy(1,MSG_LINE+1); clreol(); if(str_buff){ put_buffer(str_buff,MSG_LINE,0); command_count=0; if(++last_msg>=MAX_SAVE_MSG) last_msg=0; strncpy(old_msg[last_msg],str_buff,VTYPESIZ); old_msg[last_msg][VTYPESIZ-1]='\0'; msg_flag=TRUE; }else msg_flag=FALSE; } int get_check(char*prompt){ int res; prt(prompt,0,0); if(wherex()>MSG_LEN +1) gotoxy(74,1); cputs(" [y/n]"); do{ res=inkey(); }while(res==' '); erase_line(0,0); if(res=='Y'||res=='y') return(TRUE); else return(FALSE); } int get_com(char *prompt,char *command){ int res; if(prompt) prt(prompt,0,0); *command=inkey(); if(*command==ESCAPE) res=FALSE; else res=TRUE; erase_line(MSG_LINE,0); return(res); } void bell(void){ if (! sound_beep_flag) return; putchar('\007'); } /* the rest is just modified -ev- */ /* definitions used by screen_map() */ /* index into border character array */ #define TL 0 /* top left */ #define TR 1 #define BL 2 #define BR 3 #define HE 4 /* horizontal edge */ #define VE 5 /* character set to use */ # define CH(x) (screen_border[1][x]) /* Display highest priority object in the RATIO by RATIO area */ #define RATIO 3 void screen_map() { register int i, j; static int8u screen_border[2][6] = { {'+', '+', '+', '+', '-', '|'}, /* normal chars */ {201, 187, 200, 188, 205, 186} /* graphics chars */ }; int8u map[MAX_WIDTH / RATIO + 1]; int8u tmp; int priority[256]; int row, orow, col, myrow, mycol = 0; char prntscrnbuf[80]; for (i = 0; i < 256; i++) priority[i] = 0; priority['<'] = 5; priority['>'] = 5; priority['@'] = 10; priority[wallsym] = -5; priority[floorsym] = -10; priority['\''] = -3; priority[' '] = -15; save_screen(); clear_screen(); gotoxy(1,1); putch(CH(TL)); for (i = 0; i < MAX_WIDTH / RATIO; i++) putch(CH(HE)); putch(CH(TR)); orow = -1; map[MAX_WIDTH / RATIO] = '\0'; for (i = 0; i < MAX_HEIGHT; i++) { row = i / RATIO; if (row != orow) { if (orow >= 0) { sprintf(prntscrnbuf,"%c%s%c",CH(VE), map, CH(VE)); gotoxy(1,orow+2); cputs(prntscrnbuf); } for (j = 0; j < MAX_WIDTH / RATIO; j++) map[j] = ' '; orow = row; } for (j = 0; j < MAX_WIDTH; j++) { col = j / RATIO; tmp = loc_symbol(i, j); if (priority[map[col]] < priority[tmp]) map[col] = tmp; if (map[col] == '@') { mycol = col + 1; /* account for border */ myrow = row + 1; } } } if (orow >= 0) { sprintf(prntscrnbuf,"%c%s%c",CH(VE), map, CH(VE)); gotoxy(1,orow+2); cputs(prntscrnbuf); } gotoxy(1,orow+3); putch(CH(BL)); for (i = 0; i < MAX_WIDTH / RATIO; i++) putch(CH(HE)); putch(CH(BR)); gotoxy(24,24); cputs("Hit any key to continue"); if (mycol > 0) gotoxy(mycol+1, myrow+1); inkey(); restore_screen(); } void pause_exit(int prt_line, int delay) { char dummy; #ifdef __TURBOC__ /* Otherwise, TURBO C complains that delay is never used. */ dummy = (char) delay; #endif prt("[Press any key to continue, or Q to exit.]", prt_line, 10); dummy = inkey(); if (dummy == 'Q') { erase_line(prt_line, 0); exit_game(); } erase_line(prt_line, 0); } void pause_line(int prt_line) { prt("[Press any key to continue.]", prt_line, 23); (void) inkey(); erase_line(prt_line, 0); } moria-5.6.debian.1/ibmpc/turbo_c.inf0000644000175000017500000000164705613605103015417 0ustar pjbpjb Compiler Stats : TurboC on Compaq 386sx w/ 1Meg memory & 20Meg HD C calling convention 80286 code generation HUGE model used optimized for size Compiler Defines : MSDOS;DEBUG When compiling PC-Curses, make sure the .obj code is the same model as the source code for Umoria. Also, a size modifier letter must start the name of the .lib file (HCURSES.LIB for instance). Note that reset_term() is commented out in death.c and io.c. This is because calling this function causes moria to die horribly when moria is compiled by Turbo C. I do know what the problem is, so, for now, reset_term() is never called for the Turbo C version. The file tcio.c is an untested file meant to replace the source/io.c file. If you use tcio.c instead of source/io.c, you do not need PC-Curses. The result is a program a bit smaller, and perhaps a bit faster. You will also need to comment out the #include at the beginning of ms_ansi.c. moria-5.6.debian.1/ibmpc/TERMCAP0000644000175000017500000000247105603152200014270 0ustar pjbpjb# Termcap file for PC MORIA. This file will only be necessary if you # are using the "ANSI" option in MORIA.CNF (see README for details). # For PCs, ATs and clones, there is no reason to use the "ANSI" option # and this file can be safely discarded. For DEC Rainbow users, this # file is required. It must be either in the current directory, in # directory \ETC, or somewhere on the PATH for MORIA to find it # # Monochrome IBMPC. # This is a termcap for the NANSI.SYS device driver. # It is the same as the ANSI termcap, except NANSI supports # line insert (al) and delete (dl) while ANSI does not. # ibmpc-mono:\ :co#80:\ :li#24:\ :cl=\E[2J:\ :bs:\ :ho=\E[H:\ :cm=\E[%i%2;%2H:\ :up=\E[A:\ :do=\E[B:\ :nd=\E[C:\ :le=\E[D:\ :ce=\E[K:\ :ti=\E[m:\ :te=\E[m:\ :so=\E[1m:\ :se=\E[m:\ :us=\E[1m:\ :ue=\E[m:\ :al=\E[L:\ :dl=\E[M: # # Color IBMPC. # This is a termcap for the NANSI.SYS device driver. # It is the same as the ANSI termcap, except NANSI supports # line insert (al) and delete (dl) while ANSI does not. # # Gratiously supplied by Darren Friedlein. # ibmpc-color:\ :co#80:\ :li#24:\ :cl=\E[2J:\ :bs:\ :ho=\E[H:\ :cm=\E[%i%2;%2H:\ :up=\E[A:\ :do=\E[B:\ :nd=\E[C:\ :le=\E[D:\ :ce=\E[K:\ :ti=\E[44;37m\E1m:\ :te=\E[0m:\ :so=\E[31m:\ :se=\E[37m:\ :us=\E[33m:\ :ue=\E[37m:\ :al=\E[L:\ :dl=\E[M: moria-5.6.debian.1/ibmpc/ms_misc.c0000644000175000017500000002677511074756221015101 0ustar pjbpjb/* ibmpc/ms_misc.c: MSDOS support code Copyright (c) 1989-94 James E. Wilson, Don Kneller This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #ifdef __TURBOC__ #include #endif /* __TURBOC__ */ #include #include #include #include #include #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #ifdef MSDOS #ifndef USING_TCIO /* We don't want to include curses.h when using the tcio.c file. */ #include #endif #ifdef ANSI #include "ms_ansi.h" #endif #ifdef LINT_ARGS void exit(int); static FILE *fopenp(char *, char *, char *); static unsigned int ioctl(int ,int ,unsigned int ); #else void exit(); static unsigned int ioctl(); #endif extern char *getenv(); #define PATHLEN 80 char moriatop[PATHLEN]; char moriasav[PATHLEN]; int saveprompt = TRUE; int ibmbios; static int rawio; int8u floorsym = '.'; int8u wallsym = '#'; /* UNIX compatability routines */ void user_name(buf) char *buf; { strcpy(buf, getlogin()); } char * getlogin() { char *cp; if ((cp = getenv("USER")) == NULL) cp = "player"; return cp; } #ifndef __TURBOC__ unsigned int sleep(secs) int secs; { time_t finish_time; finish_time = time((long *) NULL) + secs; while (time((long *) NULL) < finish_time) /* nothing */; return 0; } #endif #ifdef OLD /* This is the old code. It is not strictly correct; it is retained in case the correct code below is not portable. You will also have to change the declarations for these functions in externs.h. */ void error(fmt, a1, a2, a3, a4) char *fmt; int a1, a2, a3, a4; { fprintf(stderr, "MORIA error: "); fprintf(stderr, fmt, a1, a2, a3, a4); (void) sleep(2); exit(1); } void warn(fmt, a1, a2, a3, a4) char *fmt; int a1, a2, a3, a4; { fprintf(stderr, "MORIA warning: "); fprintf(stderr, fmt, a1, a2, a3, a4); (void) sleep(2); } #else #include void error (char *fmt, ...) { va_list p_arg; va_start (p_arg, fmt); fprintf (stderr, "Moria error: "); vfprintf (stderr, fmt, p_arg); sleep (2); exit (1); } void warn(char *fmt, ...) { va_list p_arg; va_start(p_arg, fmt); fprintf(stderr, "MORIA warning: "); vfprintf(stderr, fmt, p_arg); sleep(2); } #endif /* Search the path for a file of name "name". The directory is * filled in with the directory part of the path. */ static FILE * fopenp(name, mode, directory) char *name, *mode, directory[]; { char *dp, *pathp, *getenv(), lastch; FILE *fp; /* Try the default directory first. If the file can't be opened, * start looking along the path. */ fp = fopen (name, mode); if (fp) { directory[0] = '\0'; return fp; } pathp = getenv("PATH"); while (pathp && *pathp) { dp = directory; while (*pathp && *pathp != ';') lastch = *dp++ = *pathp++; if (lastch != '\\' && lastch != '/' && lastch != ':') *dp++ = '\\'; (void) strcpy(dp, name); fp = fopen (directory, mode); if (fp) { *dp = '\0'; return fp; } if (*pathp) pathp++; } directory[0] = '\0'; return NULL; } /* Read the configuration. */ void msdos_init() { char buf[BUFSIZ], *bp, opt[PATHLEN]; int arg1, arg2, cnt; FILE *fp; buf[0] = '\0'; bp = MORIA_CNF_NAME; fp = fopenp(bp, "r", buf); (void) strcpy(moriatop, buf); (void) strcat(moriatop, MORIA_TOP_NAME); (void) strcpy(moriasav, buf); (void) strcat(moriasav, MORIA_SAV_NAME); if (fp == NULL) { warn("Can't find configuration file `%s'\n", bp); return; } printf("Reading configuration from %s%s\n", buf, bp); (void) sleep(1); while (fgets(buf, sizeof buf, fp)) { if (*buf == '#') continue; cnt = sscanf(buf, "%s", opt); /* Turbo C will return EOF when reading an empty line, MSC will correctly read a NULL character */ if (cnt == 0 || #ifdef __TURBOC__ cnt == EOF || #endif opt[0] == '\0') continue; /* Go through possible variables */ if (strcmpi(opt, "GRAPHICS") == 0) { cnt = sscanf(buf, "%*s%d %d\n", &arg1, &arg2); if (cnt != 2) warn("GRAPHICS did not contain 2 values\n"); else { wallsym = (int8u) arg1; floorsym = (int8u) arg2; /* Adjust lists that depend on '#' and '.' */ object_list[OBJ_SECRET_DOOR].tchar = wallsym; } } else if (strcmpi(opt, "SAVE") == 0) { cnt = sscanf(buf, "%*s%s", opt); if (cnt == 0) warn("SAVE option requires a filename\n"); else { bp = strchr (opt, ';'); if (bp) { *bp++ = '\0'; if (*bp == 'n' || *bp == 'N') saveprompt = FALSE; } if (opt[0]) (void) strcpy(moriasav, opt); } } else if (strcmpi(opt, "SCORE") == 0) { cnt = sscanf(buf, "%*s%s", opt); if (cnt == 0) warn("SCORE option requires a filename\n"); else (void) strcpy(moriatop, opt); } else if (strcmpi(opt, "KEYBOARD") == 0) { cnt = sscanf(buf, "%*s%s", opt); if (cnt == 0) warn("KEYBOARD option requires a value\n"); else if (strcmpi(opt, "ROGUE") == 0) rogue_like_commands = TRUE; else if (strcmpi(opt, "VMS") == 0) rogue_like_commands = FALSE; } else if (strcmpi(opt, "IBMBIOS") == 0) ibmbios = TRUE; else if (strcmpi(opt, "RAWIO") == 0) rawio = TRUE; #ifdef ANSI /* Usage: ANSI [ check_ansi [ domoveopt [ tgoto ] ] ] * where check_ansi and domoveopt are "Y"es unless explicitly * set to "N"o. Tgoto is "N"o unless set to "Y"es. */ else if (strcmpi(opt, "ANSI") == 0) { cnt=sscanf(buf, "%*s%1s%1s%1s",&opt[0],&opt[1],&opt[2]); ansi_prep(cnt < 1 || opt[0] == 'y' || opt[0] == 'Y', cnt < 2 || opt[1] == 'y' || opt[1] == 'Y', cnt >= 3 && (opt[2] == 'y' || opt[2] == 'Y')); } #endif else warn("Unknown configuration line: `%s'\n", buf); } fclose(fp); /* The only text file has been read. Switch to binary mode */ } #include #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 old_stdin, old_stdout, ioctl(); void msdos_raw() { if (!rawio) return; old_stdin = ioctl(STDIN, GETBITS, 0); old_stdout = ioctl(STDOUT, GETBITS, 0); if (old_stdin & DEVICE) ioctl(STDIN, SETBITS, old_stdin | RAW); if (old_stdout & DEVICE) ioctl(STDOUT, SETBITS, old_stdout | RAW); } void msdos_noraw() { if (!rawio) return; if (old_stdin) (void) ioctl(STDIN, SETBITS, old_stdin); if (old_stdout) (void) ioctl(STDOUT, SETBITS, old_stdout); } static unsigned int ioctl(handle, mode, setvalue) unsigned int setvalue; { union REGS regs; regs.h.ah = IOCTL; regs.h.al = (unsigned char) mode; regs.x.bx = handle; regs.h.dl = (unsigned char) setvalue; regs.h.dh = 0; /* Zero out dh */ intdos(®s, ®s); return (regs.x.dx); } /* Normal characters are output when the shift key is not pushed. * Shift characters are output when either shift key is pushed. */ #define KEYPADHI 83 #define KEYPADLOW 71 #define ISKEYPAD(x) (KEYPADLOW <= (x) && (x) <= KEYPADHI) #undef CTRL #define CTRL(x) (x - '@') typedef struct { char normal, shift, numlock; } KEY; static KEY roguekeypad[KEYPADHI - KEYPADLOW + 1] = { {'y', 'Y', CTRL('Y')}, /* 7 */ {'k', 'K', CTRL('K')}, /* 8 */ {'u', 'U', CTRL('U')}, /* 9 */ {'.', '.', '.'}, /* - */ {'h', 'H', CTRL('H')}, /* 4 */ {'.', '.', '.'}, /* 5 */ {'l', 'L', CTRL('L')}, /* 6 */ {CTRL('P'), CTRL('P'), CTRL('P')}, /* + */ {'b', 'B', CTRL('B')}, /* 1 */ {'j', 'J', CTRL('J')}, /* 2 */ {'n', 'N', CTRL('N')}, /* 3 */ {'i', 'i', 'i'}, /* Ins */ {'.', '.', '.'} /* Del */ }; static KEY originalkeypad[KEYPADHI - KEYPADLOW + 1] = { {'7', '7', '7'}, /* 7 */ {'8', '8', '8'}, /* 8 */ {'9', '9', '9'}, /* 9 */ {'-', '-', '-'}, /* - */ {'4', '4', '4'}, /* 4 */ {'5', '5', '5'}, /* 5 - move */ {'6', '6', '6'}, /* 6 */ {CTRL('M'), CTRL('M'), CTRL('M')}, /* + */ {'1', '1', '1'}, /* 1 */ {'2', '2', '2'}, /* 2 */ {'3', '3', '3'}, /* 3 */ {'i', 'i', 'i'}, /* Ins */ {'.', '.', '.'} /* Del */ }; /* bios_getch gets keys directly with a BIOS call. */ #define SHIFT (0x1 | 0x2) #define NUMLOCK 0x20 #define KEYBRD_BIOS 0x16 int bios_getch() { unsigned char scan, shift; int ch; KEY *kp; union REGS regs; if (rogue_like_commands) kp = roguekeypad; else kp = originalkeypad; /* Get scan code. */ regs.h.ah = 0; int86(KEYBRD_BIOS, ®s, ®s); ch = regs.h.al; scan = regs.h.ah; /* Get shift status. */ regs.h.ah = 2; int86(KEYBRD_BIOS, ®s, ®s); shift = regs.h.al; /* If scan code is for the keypad, translate it. */ if (ISKEYPAD(scan)) { if (shift & NUMLOCK) ch = kp[scan - KEYPADLOW].numlock; else if (shift & SHIFT) ch = kp[scan - KEYPADLOW].shift; else ch = kp[scan - KEYPADLOW].normal; } return ch; } int msdos_getch() { int ch; if (ibmbios) ch = bios_getch(); else { ch = getch(); if (ch == 0) ch = getch(); } return ch; } #if 0 /* This intro message deleted because it is obsolete. */ /* Hardcode the introductory message in */ void msdos_intro() { char buf[80]; clear_screen(); wmove(stdscr,0,0); waddstr(stdscr," *********************"); wmove(stdscr,1,0); sprintf(buf," ** Moria %d.%d **", CUR_VERSION_MAJ, CUR_VERSION_MIN); waddstr(stdscr,buf); wmove(stdscr,2,0); waddstr(stdscr," *********************"); wmove(stdscr,3,0); waddstr(stdscr," COPYRIGHT (c) Robert Alan Koeneke"); wmove(stdscr,5,0); waddstr(stdscr,"Programmers : Robert Alan Koeneke / University of Oklahoma"); wmove(stdscr,6,0); waddstr(stdscr," Jimmey Wayne Todd / University of Oklahoma"); wmove(stdscr,8,0); waddstr(stdscr,"UNIX Port : James E. Wilson / Cygnus Support"); wmove(stdscr,10,0); waddstr(stdscr,"MSDOS Port : Don Kneller / 1349 - 10th ave"); wmove(stdscr,11,0); waddstr(stdscr, " / San Francisco, CA 94122"); wmove(stdscr,12,0); waddstr(stdscr," / Dec 12, 1988"); pause_line(23); } #endif #ifdef PC_CURSES /* Seems to be a bug in PCcurses whereby it won't really clear the screen * if there are characters there it doesn't know about. */ #define VIDEOINT 0x10 void bios_clear() { union REGS regs; unsigned char nocols, activepage; #ifdef ANSI if (ansi) return; #endif /* get video attributes */ regs.h.ah = 15; int86(VIDEOINT, ®s, ®s); nocols = regs.h.ah; activepage = regs.h.bh; /* Move to lower right corner */ regs.h.ah = 2; regs.h.dh = (unsigned char) 24; regs.h.dl = nocols - 1; /* lower right col */ regs.h.bh = activepage; int86(VIDEOINT, ®s, ®s); /* get current attribute into bh */ regs.h.ah = 8; regs.h.bh = activepage; int86(VIDEOINT, ®s, ®s); regs.h.bh = regs.h.ah; regs.h.cl = 0; /* upper left row */ regs.h.ch = 0; /* upper left col */ regs.h.dh = (unsigned char) 24; /* lower right row */ regs.h.dl = nocols - 1; /* lower right col */ regs.h.al = 0; /* clear window */ regs.h.ah = 7; /* scroll down */ int86(VIDEOINT, ®s, ®s); } #endif #endif moria-5.6.debian.1/ibmpc/TCCONFIG.TCU0000644000175000017500000000454205603152202015026 0ustar pjbpjbA uuencoded copy of a TCCONFIG.TCU file. begin 640 TCCONFIG.TC M5'5R8F\@0R!#;VYF:6=U0 ! %Z $ 7L 0 ? ! %] $ M 7X 0 ?P ! & $ 8( 0 A ! "% $ <@ 0 !R0 ! #* $ M LL 0 S ! #- $ ,X 0 !SP ! #0 $ &=$ 0!DT@ ! "#5 $ M -< 0 V ! #9 $ =H 0 !VP ! #< $ -T 0 !W@ ! '? $ M . 0 X0 ! #B $ 2P!1 N M "T! M@ !$.EQ455)"3UQ#7$E.0TQ51$4 M M "X!@ !$ M.EQ455)"3UQ#7$Q)0@ M M "\!4 !534]2 M24$N4%)* M # !! S,@ ,0$% #(U M ,@$% #$P, ,P%_ $U31$]3 M M M T 1X *@ -0$> M "H #8!'@ J M W 1X *@ M . $> "H #D! M'@ J Z 1X *@ M .P$> "H M #P!'@ J ] M 8 M M ^ 00 M- #\!4 !40U!)0TLN5$, M $ ! M1 !$.EQ455)"3UQ#7$))3@ M $$!4 M 9 /__ @ : end moria-5.6.debian.1/ibmpc/CONFIG.DOC0000644000175000017500000002465511074753120014565 0ustar pjbpjb The Dungeons of MORIA version 5.x COPYRIGHT (c) Robert Alan Koeneke MSDOS port, v4.873, by D. G. Kneller Nov 1, 1988 Updated for Umoria 5.x by James E. Wilson Mar 24, 1991 Table of contents 1. USAGE ............................................................. 1 2. REQUIREMENTS ...................................................... 1 3. INSTALLATION ...................................................... 1 3.1. Hard drive systems .............................................. 1 3.2. High-density floppy systems ..................................... 2 3.3. 2 - 360K floppy systems ......................................... 2 4. OPTIONS ........................................................... 2 4.1. SAVE ............................................................ 2 4.2. SCORE ........................................................... 3 4.3. KEYBOARD ........................................................ 3 4.4. GRAPHICS ........................................................ 3 4.5. RAWIO ........................................................... 3 4.6. IBMBIOS ......................................................... 3 4.7. ANSI ............................................................ 4 5. ENVIRONMENT VARIABLES ............................................. 5 6. BUGS .............................................................. 5 7. AUTHOR'S ADDRESS .................................................. 5 - i - INTRODUCTION This README file describes the requirements and setup necessary to get MORIA running on your MSDOS computer. The actual game documentation is in MORIA.DOC. 1. USAGE Usage: moria [ -norsw ] [ savefile ] Where: -n starts a new game, ignoring any existing save files. -o selects the original (VMS) command set. -r selects the Rogue-like command set. -s prints the score file and exits. -w will try to resurrect a dead character 2. REQUIREMENTS 640K ram (really!) DOS 2.x or higher 2 - 360K floppy disk drives or 1 high density drive or 1 hard drive A 24 (or 25) line by 80 column monitor. MORIA uses either BIOS calls or ANSI for video output so should work properly on most monitors. It must use ANSI to work on DEC Rainbows. It won't work in 43-line mode of an EGA. 3. INSTALLATION MORIA is very easy to configure. The biggest problem is that there is not enough room on a single 360K floppy disk to hold the DOS system files, MORIA.EXE (about 340K) and a MORIA save file (about 20K or so). To install MORIA, some files must be copied and 2 options in MORIA.CNF must be set. Options and the MORIA.CNF are described more fully in the section entitled OPTIONS. Here are a few methods of configuration. These methods are also described in the MORIA.CNF file. 3.1. Hard drive systems Create a c:\games subdirectory on your hard disk and put c:\games on your PATH (see the DOS manual if you need help with PATH). Copy MORIA.EXE and MORIA.CNF to c:\games. Edit MORIA.CNF and put in the options: SAVE c:\games\moria.sav;n SCORE c:\games\moria.scr - 1 - 3.2. High-density floppy systems This is about as easy as for a hard disk. Format a diskette and put the DOS system files on it (use FORMAT A:/S). Copy MORIA.EXE and MORIA.CNF to that diskette. Edit MORIA.CNF and put in the options: SAVE a:\moria.sav SCORE a:\moria.scr 3.3. 2 - 360K floppy systems You will need to use 2 floppy diskettes. Format a diskette and put the DOS system files on it (use FORMAT A:/S). Copy MORIA.CNF to this diskette. This diskette will go in drive A when you want to play MORIA. Format a second diskette (no /S) and copy MORIA.EXE to it. This diskette will go in drive B. Edit MORIA.CNF and put in the options: SAVE a:moria.sav SCORE a:moria.scr When you want to play MORIA, put both diskettes in and type "B:MORIA" 4. OPTIONS When MORIA starts up it looks along your PATH for the file "MORIA.CNF". MORIA.CNF contains configuration information for MORIA in the form of options. Options have a name and perhaps a value. If the option doesn't have a value, simply mentioning its name selects that option. Here are the options. 4.1. SAVE The SAVE option has 1 argument, the name of a file where saved games will be stored. Normally, when you start MORIA by typing "MORIA file", MORIA will try to use "file" as the name of a saved game. The SAVE option allows you to give the name of the save file so you don't have to type it in each time you save or restore a game. A sample SAVE option is: SAVE c:\games\moria.sav;n The ";n" is optional. If given it means that MORIA should never prompt you for the name of the save file. If the SAVE option isn't given, MORIA defaults to the file MORIA.SAV in the same directory as MORIA.CNF. Also, the SAVE option can be just ";n", which means use the default name without prompting. - 2 - 4.2. SCORE The SCORE option has 1 argument, the name of the file where the top scores are kept. A sample SCORE option is: SCORE c:\games\moria.scr If the SCORE option isn't given, MORIA defaults to the file MORIA.SCR in the same directory as MORIA.CNF. 4.3. KEYBOARD MORIA can be played with either of 2 styles of commands. There is the original VMS-style commands and a Rogue-style set of commands. The choice of command set affects the keyboard letters used for doing the various game commands. The KEYBOARD value can be either "ROGUE" or "VMS". The default is to use the original VMS-style commands. 4.4. GRAPHICS The GRAPHICS option takes 2 arguments, the ASCII number for the character to be used for displaying the walls and floors. For example, to use '#' for the walls and '.' for the floors, the GRAPHICS option would be: GRAPHICS 35 46 Incidentally, these also are the default characters that are used if the GRAPHICS option is not specified. 4.5. RAWIO Normally DOS does some extra work whenever a character is input from the keyboard. One of the tasks is to interpret the special characters ^S (control-S, which does a scroll lock) ^C (control-C, which acts like control-Break) and ^P (control-P, which acts like control-PrtSc, toggling output to your printer or giving an error message if you don't have one). The RAWIO option will be used to tell DOS to not do this extra work by making the input (and output) operate in "raw" mode. This is good because ^P (a MORIA command) will now work. As well, screen output will be somewhat faster. URGENT! RAWIO will not work on Dec Rainbows and will probably lock up the computer. 4.6. IBMBIOS IBMBIOS enables the use of a BIOS call to read input from the keyboard. - 3 - The advantage of this is that the numeric keypad will then be useable as direction keys for moving around. With this option the keypad keys map to the directions: 7 up & left 8 up 9 up & right 4 left 5 nothing 6 right 1 down & left 2 down 3 down & right And other keypad keys map to: - rest + previous message Ins inventory Del rest If you are using the Rogue-style command set, the shift key and NumLock key modify these commands. With the shift key down, 7 will be "run up and left", 8 will be "run up", etc. The NumLock key is used as a toggle between moving and tunneling. With NumLock enabled, 7 will be "tunnel up and left", etc. 4.7. ANSI The ANSI option tells MORIA to use ANSI sequences rather than using BIOS calls for doing output. You must use the ANSI option if you are playing MORIA on a DEC Rainbow. On IBM PCs, ATs and clones there should be no need to use this option and you can safely ignore the rest of this section. The ANSI option takes three optional arguments: check_ansi, move_opt and use_tgoto. If no arguments are given, they are assumed to be Y (yes), Y, and N (no), respectively. The usage is ANSI [ check_ansi [ move_opt [ use_tgoto ] ] ] An example is: ANSI Y N check_ansi tells MORIA to check for ANSI.SYS when starting up. You may have to disable this check if MORIA insists you don't have ANSI installed, but you know you do. move_opt tries to reduce the amount of output being sent to the screen. use_tgoto tells MORIA to use the actual TERMCAP tgoto() routine. The default is to use a faster routine which only works for ANSI-like terminals. When the ANSI option is chosen, MORIA looks for ANSI control strings in a file called TERMCAP, first in the current directory, then in directory ETC. A sample TERMCAP file is supplied. Basically, this file maps between logical cursor operations (eg. "cursor up") to ANSI sequences (eg ESC [ A). In the file, ESC (escape) is represented as \E. MORIA uses the following logical operations: - 4 - ce clear to end of line cl clear screen cm cursor motion (only if use_tgoto is chosen) nd cursor forward (non-destructive space) le cursor back (left) up cursor up do cursor down li number of lines on the screen MORIA can also use: ti terminal initialization string te terminal end string 5. ENVIRONMENT VARIABLES MORIA uses the environment variable USER to determine your real name (as opposed to your role playing name in the game). The USER environment variable can be set from DOS with: set USER = kneller If the USER variable isn't set, MORIA just uses the name "player". If the ANSI option is chosen, MORIA uses the variable TERM to determine the terminal information to extract from the TERMCAP file. If the TERM variable isn't set, MORIA assumes the value "ibmpc-mono". 6. BUGS I have not played this game much so there may be bugs which I have not seen yet. Please report them to me so I can fix them. 7. AUTHOR'S ADDRESS If you have any questions or bug reports please contact the author of the current version at: David Grabiner grabiner@alumni.princeton.edu The original author can be reached at: James E. Wilson 856 University Ave. Palo Alto, CA 94301 USA or by electronic mail: wilson@kithrup.com - 5 - moria-5.6.debian.1/ibmpc/MLINK.LNK0000644000175000017500000000041405603152200014465 0ustar pjbpjbMAIN+CREATE+CREATURE+DEATH+DESC+DUNGEON+ EAT+FILES+GENERATE+HELP+MAGIC+ MISC1+MISC2+MONSTERS+MORIA1+MORIA2+ POTIONS+PRAYER+RND+SAVE+ SCROLLS+SETS+SIGNALS+SPELLS+STAFFS+ STORE1+STORE2+TREASURE+VARIABLE+ WANDS+WIZARD+IO+MS_MISC+RECALL+ PLAYER.C+TABLES.C,moria,,pccurses moria-5.6.debian.1/ibmpc/TCPICK.TCU0000644000175000017500000000326305603152202014606 0ustar pjbpjbA uuencoded copy of a TCPICK.TC file. begin 640 TCPICK.TC M5'5R8F\@0R!0:6-K($QI 0 M -,D %P- X <) M-!-)$P"!- (]: ,!< ,!. */ #include #include #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #ifdef USG #ifndef ATARIST_MWC #include #endif #else #include #endif #include #if defined(LINT_ARGS) static int look_ray(int, int, int); static int look_see(int, int, int *); static void inven_throw(int, struct inven_type *); static void facts(struct inven_type *, int *, int *, int *, int *); static void drop_throw(int, int, struct inven_type *); static void py_bash(int, int); #else static int look_ray(); static int look_see(); #endif /* Tunnels through rubble and walls -RAK- */ /* Must take into account: secret doors, special tools */ void tunnel(dir) int dir; { register int i, tabil; register cave_type *c_ptr; register inven_type *i_ptr; int y, x; monster_type *m_ptr; vtype out_val, m_name; #ifdef ATARIST_MWC int32u holder; #endif if ((py.flags.confused > 0) && /* Confused? */ (randint(4) > 1)) /* 75% random movement */ dir = randint(9); y = char_row; x = char_col; (void) mmove(dir, &y, &x); c_ptr = &cave[y][x]; /* Compute the digging ability of player; based on */ /* strength, and type of tool used */ tabil = py.stats.use_stat[A_STR]; i_ptr = &inventory[INVEN_WIELD]; /* Don't let the player tunnel somewhere illegal, this is necessary to prevent the player from getting a free attack by trying to tunnel somewhere where it has no effect. */ if (c_ptr->fval < MIN_CAVE_WALL && (c_ptr->tptr == 0 || (t_list[c_ptr->tptr].tval != TV_RUBBLE && t_list[c_ptr->tptr].tval != TV_SECRET_DOOR))) { if (c_ptr->tptr == 0) { msg_print ("Tunnel through what? Empty air?!?"); free_turn_flag = TRUE; } else { msg_print("You can't tunnel through that."); free_turn_flag = TRUE; } return; } if (c_ptr->cptr > 1) { m_ptr = &m_list[c_ptr->cptr]; if (m_ptr->ml) (void) sprintf (m_name, "The %s", c_list[m_ptr->mptr].name); else (void) strcpy (m_name, "Something"); (void) sprintf(out_val, "%s is in your way!", m_name); msg_print(out_val); /* let the player attack the creature */ if (py.flags.afraid < 1) py_attack(y, x); else msg_print("You are too afraid!"); } else if (i_ptr->tval != TV_NOTHING) { #ifdef ATARIST_MWC if ((holder = TR_TUNNEL) & i_ptr->flags) #else if (TR_TUNNEL & i_ptr->flags) #endif tabil += 25 + i_ptr->p1*50; else { tabil += (i_ptr->damage[0]*i_ptr->damage[1]) + i_ptr->tohit + i_ptr->todam; /* divide by two so that digging without shovel isn't too easy */ tabil >>= 1; } /* If this weapon is too heavy for the player to wield properly, then also make it harder to dig with it. */ if (weapon_heavy) { tabil += (py.stats.use_stat[A_STR] * 15) - i_ptr->weight; if (tabil < 0) tabil = 0; } /* Regular walls; Granite, magma intrusion, quartz vein */ /* Don't forget the boundary walls, made of titanium (255)*/ switch(c_ptr->fval) { case GRANITE_WALL: i = randint(1200) + 80; if (twall(y, x, tabil, i)) msg_print("You have finished the tunnel."); else count_msg_print("You tunnel into the granite wall."); break; case MAGMA_WALL: i = randint(600) + 10; if (twall(y, x, tabil, i)) msg_print("You have finished the tunnel."); else count_msg_print("You tunnel into the magma intrusion."); break; case QUARTZ_WALL: i = randint(400) + 10; if (twall(y, x, tabil, i)) msg_print("You have finished the tunnel."); else count_msg_print("You tunnel into the quartz vein."); break; case BOUNDARY_WALL: msg_print("This seems to be permanent rock."); break; default: /* Is there an object in the way? (Rubble and secret doors)*/ if (c_ptr->tptr != 0) { /* Rubble. */ if (t_list[c_ptr->tptr].tval == TV_RUBBLE) { if (tabil > randint(180)) { (void) delete_object(y, x); msg_print("You have removed the rubble."); if (randint(10) == 1) { place_object(y, x, FALSE); if (test_light(y, x)) msg_print("You have found something!"); } lite_spot(y, x); } else count_msg_print("You dig in the rubble."); } /* Secret doors.*/ else if (t_list[c_ptr->tptr].tval == TV_SECRET_DOOR) { count_msg_print("You tunnel into the granite wall."); search(char_row, char_col, py.misc.srh); } else abort (); } else abort (); break; } } else msg_print("You dig with your hands, making no progress."); } /* Disarms a trap -RAK- */ void disarm_trap() { int y, x, level, tmp, dir, no_disarm; register int tot, i; register cave_type *c_ptr; register inven_type *i_ptr; monster_type *m_ptr; vtype m_name, out_val; y = char_row; x = char_col; if (get_dir(CNIL, &dir)) { (void) mmove(dir, &y, &x); c_ptr = &cave[y][x]; no_disarm = FALSE; if (c_ptr->cptr > 1 && c_ptr->tptr != 0 && (t_list[c_ptr->tptr].tval == TV_VIS_TRAP || t_list[c_ptr->tptr].tval == TV_CHEST)) { m_ptr = &m_list[c_ptr->cptr]; if (m_ptr->ml) (void) sprintf (m_name, "The %s", c_list[m_ptr->mptr].name); else (void) strcpy (m_name, "Something"); (void) sprintf(out_val, "%s is in your way!", m_name); msg_print(out_val); } else if (c_ptr->tptr != 0) { tot = py.misc.disarm + 2*todis_adj() + stat_adj(A_INT) + (class_level_adj[py.misc.pclass][CLA_DISARM] * py.misc.lev / 3); if ((py.flags.blind > 0) || (no_light())) tot = tot / 10; if (py.flags.confused > 0) tot = tot / 10; if (py.flags.image > 0) tot = tot / 10; i_ptr = &t_list[c_ptr->tptr]; i = i_ptr->tval; level = i_ptr->level; if (i == TV_VIS_TRAP) /* Floor trap */ { if ((tot + 100 - level) > randint(100)) { msg_print("You have disarmed the trap."); py.misc.exp += i_ptr->p1; (void) delete_object(y, x); /* make sure we move onto the trap even if confused */ tmp = py.flags.confused; py.flags.confused = 0; move_char(dir, FALSE); py.flags.confused = tmp; prt_experience(); } /* avoid randint(0) call */ else if ((tot > 5) && (randint(tot) > 5)) count_msg_print("You failed to disarm the trap."); else { msg_print("You set the trap off!"); /* make sure we move onto the trap even if confused */ tmp = py.flags.confused; py.flags.confused = 0; move_char(dir, FALSE); py.flags.confused += tmp; } } else if (i == TV_CHEST) { if (!known2_p(i_ptr)) { msg_print("I don't see a trap."); free_turn_flag = TRUE; } else if (CH_TRAPPED & i_ptr->flags) { if ((tot - level) > randint(100)) { i_ptr->flags &= ~CH_TRAPPED; if (CH_LOCKED & i_ptr->flags) i_ptr->name2 = SN_LOCKED; else i_ptr->name2 = SN_DISARMED; msg_print("You have disarmed the chest."); known2(i_ptr); py.misc.exp += level; prt_experience(); } else if ((tot > 5) && (randint(tot) > 5)) count_msg_print("You failed to disarm the chest."); else { msg_print("You set a trap off!"); known2(i_ptr); chest_trap(y, x); } } else { msg_print("The chest was not trapped."); free_turn_flag = TRUE; } } else no_disarm = TRUE; } else no_disarm = TRUE; if (no_disarm) { msg_print("I do not see anything to disarm there."); free_turn_flag = TRUE; } } } /* An enhanced look, with peripheral vision. Looking all 8 -CJS- directions will see everything which ought to be visible. Can specify direction 5, which looks in all directions. For the purpose of hindering vision, each place is regarded as a diamond just touching its four immediate neighbours. A diamond is opaque if it is a wall, or shut door, or something like that. A place is visible if any part of its diamond is visible: i.e. there is a line from the view point to part of the diamond which does not pass through any opaque diamonds. Consider the following situation: @.... X X X X X .##.. / \ / \ / \ / \ / \ ..... X @ X . X . X 1 X . X \ / \ / \ / \ / \ / X X X X X Expanded view, with / \ / \ / \ / \ / \ diamonds inscribed X . X # X # X 2 X . X about each point, \ / \ / \ / \ / \ / and some locations X X X X X numbered. / \ / \ / \ / \ / \ X . X . X . X 3 X 4 X \ / \ / \ / \ / \ / X X X X X - Location 1 is fully visible. - Location 2 is visible, even though partially obscured. - Location 3 is invisible, but if either # were transparent, it would be visible. - Location 4 is completely obscured by a single #. The function which does the work is look_ray. It sets up its own co-ordinate frame (global variables map back to the dungeon frame) and looks for everything between two angles specified from a central line. It is recursive, and each call looks at stuff visible along a line parallel to the center line, and a set distance away from it. A diagonal look uses more extreme peripheral vision from the closest horizontal and vertical directions; horizontal or vertical looks take a call for each side of the central line. */ /* Globally accessed variables: gl_nseen counts the number of places where something is seen. gl_rock indicates a look for rock or objects. The others map co-ords in the ray frame to dungeon co-ords. dungeon y = char_row + gl_fyx * (ray x) + gl_fyy * (ray y) dungeon x = char_col + gl_fxx * (ray x) + gl_fxy * (ray y) */ static int gl_fxx, gl_fxy, gl_fyx, gl_fyy; static int gl_nseen, gl_noquery; static int gl_rock; /* Intended to be indexed by dir/2, since is only relevant to horizontal or vertical directions. */ static int set_fxy[] = { 0, 1, 0, 0, -1 }; static int set_fxx[] = { 0, 0, -1, 1, 0 }; static int set_fyy[] = { 0, 0, 1, -1, 0 }; static int set_fyx[] = { 0, 1, 0, 0, -1 }; /* Map diagonal-dir/2 to a normal-dir/2. */ static int map_diag1[] = { 1, 3, 0, 2, 4 }; static int map_diag2[] = { 2, 1, 0, 4, 3 }; #define GRADF 10000 /* Any sufficiently big number will do */ /* Look at what we can see. This is a free move. Prompts for a direction, and then looks at every object in turn within a cone of vision in that direction. For each object, the cursor is moved over the object, a description is given, and we wait for the user to type something. Typing ESCAPE will abort the entire look. Looks first at real objects and monsters, and looks at rock types only after all other things have been seen. Only looks at rock types if the highlight_seams option is set. */ void look() { register int i, abort; int dir, dummy; if (py.flags.blind > 0) msg_print("You can't see a damn thing!"); else if (py.flags.image > 0) msg_print("You can't believe what you are seeing! It's like a dream!"); else if (get_alldir("Look which direction?", &dir)) { abort = FALSE; gl_nseen = 0; gl_rock = 0; gl_noquery = FALSE; /* Have to set this up for the look_see */ if (look_see(0, 0, &dummy)) abort = TRUE; else { do { abort = FALSE; if (dir == 5) { for (i = 1; i <= 4; i++) { gl_fxx = set_fxx[i]; gl_fyx = set_fyx[i]; gl_fxy = set_fxy[i]; gl_fyy = set_fyy[i]; if (look_ray(0, 2*GRADF-1, 1)) { abort = TRUE; break; } gl_fxy = -gl_fxy; gl_fyy = -gl_fyy; if (look_ray(0, 2*GRADF, 2)) { abort = TRUE; break; } } } else if ((dir & 1) == 0) /* Straight directions */ { i = dir >> 1; gl_fxx = set_fxx[i]; gl_fyx = set_fyx[i]; gl_fxy = set_fxy[i]; gl_fyy = set_fyy[i]; if (look_ray(0, GRADF, 1)) abort = TRUE; else { gl_fxy = -gl_fxy; gl_fyy = -gl_fyy; abort = look_ray(0, GRADF, 2); } } else { i = map_diag1[dir >> 1]; gl_fxx = set_fxx[i]; gl_fyx = set_fyx[i]; gl_fxy = -set_fxy[i]; gl_fyy = -set_fyy[i]; if (look_ray(1, 2*GRADF, GRADF)) abort = TRUE; else { i = map_diag2[dir >> 1]; gl_fxx = set_fxx[i]; gl_fyx = set_fyx[i]; gl_fxy = set_fxy[i]; gl_fyy = set_fyy[i]; abort = look_ray(1, 2*GRADF-1, GRADF); } } } while (abort == FALSE && highlight_seams && (++gl_rock < 2)); if (abort) msg_print("--Aborting look--"); else { if (gl_nseen) { if (dir == 5) msg_print("That's all you see."); else msg_print("That's all you see in that direction."); } else if (dir == 5) msg_print("You see nothing of interest."); else msg_print("You see nothing of interest in that direction."); } } } } /* Look at everything within a cone of vision between two ray lines emanating from the player, and y or more places away from the direct line of view. This is recursive. Rays are specified by gradients, y over x, multiplied by 2*GRADF. This is ONLY called with gradients between 2*GRADF (45 degrees) and 1 (almost horizontal). (y axis)/ angle from ^ / ___ angle to | / ___ ...|../.....___.................... parameter y (look at things in the | / ___ cone, and on or above this line) |/ ___ @--------------------> direction in which you are looking. (x axis) | | */ static int look_ray(y, from, to) int y, from, to; { register int max_x, x; int transparent; /* from is the larger angle of the ray, since we scan towards the center line. If from is smaller, then the ray does not exist. */ if (from <= to || y > MAX_SIGHT) return FALSE; /* Find first visible location along this line. Minimum x such that (2x-1)/x < from/GRADF <=> x > GRADF(2x-1)/from. This may be called with y=0 whence x will be set to 0. Thus we need a special fix. */ x = (int)((long)GRADF * (2 * y - 1) / from + 1); if (x <= 0) x = 1; /* Find last visible location along this line. Maximum x such that (2x+1)/x > to/GRADF <=> x < GRADF(2x+1)/to */ max_x = (int)(((long)GRADF * (2 * y + 1) - 1) / to); if (max_x > MAX_SIGHT) max_x = MAX_SIGHT; if (max_x < x) return FALSE; /* gl_noquery is a HACK to prevent doubling up on direct lines of sight. If 'to' is greater than 1, we do not really look at stuff along the direct line of sight, but we do have to see what is opaque for the purposes of obscuring other objects. */ if (y == 0 && to > 1 || y == x && from < GRADF*2) gl_noquery = TRUE; else gl_noquery = FALSE; if (look_see(x, y, &transparent)) return TRUE; if (y == x) gl_noquery = FALSE; if (transparent) goto init_transparent; for (;;) { /* Look down the window we've found. */ if (look_ray(y+1, from, (int)((2 * y + 1) * (long)GRADF / x))) return TRUE; /* Find the start of next window. */ do { if (x == max_x) return FALSE; /* See if this seals off the scan. (If y is zero, then it will.) */ from = (int)((2 * y - 1) * (long)GRADF / x); if (from <= to) return FALSE; x++; if (look_see(x, y, &transparent)) return TRUE; } while(!transparent); init_transparent: /* Find the end of this window of visibility. */ do { if (x == max_x) /* The window is trimmed by an earlier limit. */ return look_ray(y+1, from, to); x++; if (look_see(x, y, &transparent)) return TRUE; } while(transparent); } } static int look_see(x, y, transparent) register int x, y; int *transparent; { char *dstring, *string, query; register cave_type *c_ptr; register int j; bigvtype out_val, tmp_str; if (x < 0 || y < 0 || y > x) { (void) sprintf(tmp_str, "Illegal call to look_see(%d, %d)", x, y); msg_print(tmp_str); } if (x == 0 && y == 0) dstring = "You are on"; else dstring = "You see"; j = char_col + gl_fxx * x + gl_fxy * y; y = char_row + gl_fyx * x + gl_fyy * y; x = j; if (!panel_contains(y, x)) { *transparent = FALSE; return FALSE; } c_ptr = &cave[y][x]; *transparent = c_ptr->fval <= MAX_OPEN_SPACE; if (gl_noquery) return FALSE; /* Don't look at a direct line of sight. A hack. */ out_val[0] = 0; if (gl_rock == 0 && c_ptr->cptr > 1 && m_list[c_ptr->cptr].ml) { j = m_list[c_ptr->cptr].mptr; (void) sprintf(out_val, "%s %s %s. [(r)ecall]", dstring, is_a_vowel( c_list[j].name[0] ) ? "an" : "a", c_list[j].name); dstring = "It is on"; prt(out_val, 0, 0); move_cursor_relative(y, x); query = inkey(); if (query == 'r' || query == 'R') { save_screen(); query = roff_recall(j); restore_screen(); } } if (c_ptr->tl || c_ptr->pl || c_ptr->fm) { if (c_ptr->tptr != 0) { if (t_list[c_ptr->tptr].tval == TV_SECRET_DOOR) goto granite; if (gl_rock ==0 && t_list[c_ptr->tptr].tval != TV_INVIS_TRAP) { objdes(tmp_str, &t_list[c_ptr->tptr], TRUE); (void) sprintf(out_val, "%s %s ---pause---", dstring, tmp_str); dstring = "It is in"; prt(out_val, 0, 0); move_cursor_relative(y, x); query = inkey(); } } if ((gl_rock || out_val[0]) && c_ptr->fval >= MIN_CLOSED_SPACE) { switch(c_ptr->fval) { case BOUNDARY_WALL: case GRANITE_WALL: granite: /* Granite is only interesting if it contains something. */ if(out_val[0]) string = "a granite wall"; else string = CNIL; /* In case we jump here */ break; case MAGMA_WALL: string = "some dark rock"; break; case QUARTZ_WALL: string = "a quartz vein"; break; default: string = CNIL; break; } if (string) { (void) sprintf(out_val, "%s %s ---pause---", dstring, string); prt(out_val, 0, 0); move_cursor_relative(y, x); query = inkey(); } } } if (out_val[0]) { gl_nseen++; if (query == ESCAPE) return TRUE; } return FALSE; } static void inven_throw(item_val, t_ptr) int item_val; inven_type *t_ptr; { register inven_type *i_ptr; #ifdef ATARIST_MWC int32u holder; #endif i_ptr = &inventory[item_val]; *t_ptr = *i_ptr; if (i_ptr->number > 1) { t_ptr->number = 1; i_ptr->number--; inven_weight -= i_ptr->weight; #ifdef ATARIST_MWC py.flags.status |= (holder = PY_STR_WGT); #else py.flags.status |= PY_STR_WGT; #endif } else inven_destroy(item_val); } /* Obtain the hit and damage bonuses and the maximum distance for a thrown missile. */ static void facts(i_ptr, tbth, tpth, tdam, tdis) register inven_type *i_ptr; int *tbth, *tpth, *tdam, *tdis; { register int tmp_weight; if (i_ptr->weight < 1) tmp_weight = 1; else tmp_weight = i_ptr->weight; /* Throwing objects */ *tdam = pdamroll(i_ptr->damage) + i_ptr->todam; *tbth = py.misc.bthb * 75 / 100; *tpth = py.misc.ptohit + i_ptr->tohit; /* Add this back later if the correct throwing device. -CJS- */ if (inventory[INVEN_WIELD].tval != TV_NOTHING) *tpth -= inventory[INVEN_WIELD].tohit; *tdis = (((py.stats.use_stat[A_STR]+20)*10)/tmp_weight); if (*tdis > 10) *tdis = 10; /* multiply damage bonuses instead of adding, when have proper missile/weapon combo, this makes them much more useful */ /* Using Bows, slings, or crossbows */ if (inventory[INVEN_WIELD].tval == TV_BOW) switch(inventory[INVEN_WIELD].p1) { case 1: if (i_ptr->tval == TV_SLING_AMMO) /* Sling and ammo */ { *tbth = py.misc.bthb; *tpth += 2 * inventory[INVEN_WIELD].tohit; *tdam += inventory[INVEN_WIELD].todam; *tdam = *tdam * 2; *tdis = 20; } break; case 2: if (i_ptr->tval == TV_ARROW) /* Short Bow and Arrow */ { *tbth = py.misc.bthb; *tpth += 2 * inventory[INVEN_WIELD].tohit; *tdam += inventory[INVEN_WIELD].todam; *tdam = *tdam * 2; *tdis = 25; } break; case 3: if (i_ptr->tval == TV_ARROW) /* Long Bow and Arrow */ { *tbth = py.misc.bthb; *tpth += 2 * inventory[INVEN_WIELD].tohit; *tdam += inventory[INVEN_WIELD].todam; *tdam = *tdam * 3; *tdis = 30; } break; case 4: if (i_ptr->tval == TV_ARROW) /* Composite Bow and Arrow*/ { *tbth = py.misc.bthb; *tpth += 2 * inventory[INVEN_WIELD].tohit; *tdam += inventory[INVEN_WIELD].todam; *tdam = *tdam * 4; *tdis = 35; } break; case 5: if (i_ptr->tval == TV_BOLT) /* Light Crossbow and Bolt*/ { *tbth = py.misc.bthb; *tpth += 2 * inventory[INVEN_WIELD].tohit; *tdam += inventory[INVEN_WIELD].todam; *tdam = *tdam * 3; *tdis = 25; } break; case 6: if (i_ptr->tval == TV_BOLT) /* Heavy Crossbow and Bolt*/ { *tbth = py.misc.bthb; *tpth += 2 * inventory[INVEN_WIELD].tohit; *tdam += inventory[INVEN_WIELD].todam; *tdam = *tdam * 4; *tdis = 35; } break; } } static void drop_throw(y, x, t_ptr) int y, x; inven_type *t_ptr; { register int i, j, k; int flag, cur_pos; bigvtype out_val, tmp_str; register cave_type *c_ptr; flag = FALSE; i = y; j = x; k = 0; if (randint(10) > 1) { do { if (in_bounds(i, j)) { c_ptr = &cave[i][j]; if (c_ptr->fval <= MAX_OPEN_SPACE && c_ptr->tptr == 0) flag = TRUE; } if (!flag) { i = y + randint(3) - 2; j = x + randint(3) - 2; k++; } } while ((!flag) && (k <= 9)); } if (flag) { cur_pos = popt(); cave[i][j].tptr = cur_pos; t_list[cur_pos] = *t_ptr; lite_spot(i, j); } else { objdes(tmp_str, t_ptr, FALSE); (void) sprintf(out_val, "The %s disappears.", tmp_str); msg_print(out_val); } } /* Throw an object across the dungeon. -RAK- */ /* Note: Flasks of oil do fire damage */ /* Note: Extra damage and chance of hitting when missiles are used*/ /* with correct weapon. I.E. wield bow and throw arrow. */ void throw_object() { int item_val, tbth, tpth, tdam, tdis; int y, x, oldy, oldx, cur_dis, dir; int flag, visible; bigvtype out_val, tmp_str; inven_type throw_obj; register cave_type *c_ptr; register monster_type *m_ptr; register int i; char tchar; if (inven_ctr == 0) { msg_print("But you are not carrying anything."); free_turn_flag = TRUE; } else if (get_item(&item_val, "Fire/Throw which one?", 0, inven_ctr-1, CNIL, CNIL)) { if (get_dir(CNIL, &dir)) { desc_remain(item_val); if (py.flags.confused > 0) { msg_print("You are confused."); do { dir = randint(9); } while (dir == 5); } inven_throw(item_val, &throw_obj); facts(&throw_obj, &tbth, &tpth, &tdam, &tdis); tchar = throw_obj.tchar; flag = FALSE; y = char_row; x = char_col; oldy = char_row; oldx = char_col; cur_dis = 0; do { (void) mmove(dir, &y, &x); cur_dis++; lite_spot(oldy, oldx); if (cur_dis > tdis) flag = TRUE; c_ptr = &cave[y][x]; if ((c_ptr->fval <= MAX_OPEN_SPACE) && (!flag)) { if (c_ptr->cptr > 1) { flag = TRUE; m_ptr = &m_list[c_ptr->cptr]; tbth = tbth - cur_dis; /* if monster not lit, make it much more difficult to hit, subtract off most bonuses, and reduce bthb depending on distance */ if (!m_ptr->ml) tbth = (tbth / (cur_dis+2)) - (py.misc.lev * class_level_adj[py.misc.pclass][CLA_BTHB] / 2) - (tpth * (BTH_PLUS_ADJ-1)); if (test_hit(tbth, (int)py.misc.lev, tpth, (int)c_list[m_ptr->mptr].ac, CLA_BTHB)) { i = m_ptr->mptr; objdes(tmp_str, &throw_obj, FALSE); /* Does the player know what he's fighting? */ if (!m_ptr->ml) { (void) sprintf(out_val, "You hear a cry as the %s finds a mark.", tmp_str); visible = FALSE; } else { (void) sprintf(out_val, "The %s hits the %s.", tmp_str, c_list[i].name); visible = TRUE; } msg_print(out_val); tdam = tot_dam(&throw_obj, tdam, i); tdam = critical_blow((int)throw_obj.weight, tpth, tdam, CLA_BTHB); if (tdam < 0) tdam = 0; i = mon_take_hit((int)c_ptr->cptr, tdam); if (i >= 0) { if (!visible) msg_print("You have killed something!"); else { (void) sprintf(out_val,"You have killed the %s.", c_list[i].name); msg_print(out_val); } prt_experience(); } } else drop_throw(oldy, oldx, &throw_obj); } else { /* do not test c_ptr->fm here */ if (panel_contains(y, x) && (py.flags.blind < 1) && (c_ptr->tl || c_ptr->pl)) { print(tchar, y, x); put_qio(); /* show object moving */ } } } else { flag = TRUE; drop_throw(oldy, oldx, &throw_obj); } oldy = y; oldx = x; } while (!flag); } } } /* Make a bash attack on someone. -CJS- Used to be part of bash above. */ static void py_bash(y, x) int y, x; { int monster, k, avg_max_hp, base_tohit; register creature_type *c_ptr; register monster_type *m_ptr; vtype m_name, out_val; monster = cave[y][x].cptr; m_ptr = &m_list[monster]; c_ptr = &c_list[m_ptr->mptr]; m_ptr->csleep = 0; /* Does the player know what he's fighting? */ if (!m_ptr->ml) (void) strcpy(m_name, "it"); else (void) sprintf(m_name, "the %s", c_ptr->name); base_tohit = py.stats.use_stat[A_STR] + inventory[INVEN_ARM].weight/2 + py.misc.wt/10; if (!m_ptr->ml) base_tohit = (base_tohit / 2) - (py.stats.use_stat[A_DEX]*(BTH_PLUS_ADJ-1)) - (py.misc.lev * class_level_adj[py.misc.pclass][CLA_BTH] / 2); if (test_hit(base_tohit, (int)py.misc.lev, (int)py.stats.use_stat[A_DEX], (int)c_ptr->ac, CLA_BTH)) { (void) sprintf(out_val, "You hit %s.", m_name); msg_print(out_val); k = pdamroll(inventory[INVEN_ARM].damage); k = critical_blow((int)(inventory[INVEN_ARM].weight / 4 + py.stats.use_stat[A_STR]), 0, k, CLA_BTH); k += py.misc.wt/60 + 3; if (k < 0) k = 0; /* See if we done it in. */ if (mon_take_hit(monster, k) >= 0) { (void) sprintf(out_val, "You have slain %s.", m_name); msg_print(out_val); prt_experience(); } else { m_name[0] = toupper((int)m_name[0]); /* Capitalize */ /* Can not stun Balrog */ avg_max_hp = (c_ptr->cdefense & CD_MAX_HP ? c_ptr->hd[0] * c_ptr->hd[1] : (c_ptr->hd[0] * (c_ptr->hd[1] + 1)) >> 1); if ((100 + randint(400) + randint(400)) > (m_ptr->hp + avg_max_hp)) { m_ptr->stunned += randint(3) + 1; if (m_ptr->stunned > 24) m_ptr->stunned = 24; (void) sprintf(out_val, "%s appears stunned!", m_name); } else (void) sprintf(out_val, "%s ignores your bash!", m_name); msg_print(out_val); } } else { (void) sprintf(out_val, "You miss %s.", m_name); msg_print(out_val); } if (randint(150) > py.stats.use_stat[A_DEX]) { msg_print("You are off balance."); py.flags.paralysis = 1 + randint(2); } } /* Bash open a door or chest -RAK- */ /* Note: Affected by strength and weight of character For a closed door, p1 is positive if locked; negative if stuck. A disarm spell unlocks and unjams doors! For an open door, p1 is positive for a broken door. A closed door can be opened - harder if locked. Any door might be bashed open (and thereby broken). Bashing a door is (potentially) faster! You move into the door way. To open a stuck door, it must be bashed. A closed door can be jammed (which makes it stuck if previously locked). Creatures can also open doors. A creature with open door ability will (if not in the line of sight) move though a closed or secret door with no changes. If in the line of sight, closed door are openned, & secret door revealed. Whether in the line of sight or not, such a creature may unlock or unstick a door. A creature with no such ability will attempt to bash a non-secret door. */ void bash() { int y, x, dir, tmp; register cave_type *c_ptr; register inven_type *t_ptr; y = char_row; x = char_col; if (get_dir(CNIL, &dir)) { if (py.flags.confused > 0) { msg_print("You are confused."); do { dir = randint(9); } while (dir == 5); } (void) mmove(dir, &y, &x); c_ptr = &cave[y][x]; if (c_ptr->cptr > 1) { if (py.flags.afraid > 0) msg_print("You are afraid!"); else py_bash(y, x); } else if (c_ptr->tptr != 0) { t_ptr = &t_list[c_ptr->tptr]; if (t_ptr->tval == TV_CLOSED_DOOR) { count_msg_print("You smash into the door!"); tmp = py.stats.use_stat[A_STR] + py.misc.wt / 2; /* Use (roughly) similar method as for monsters. */ if (randint(tmp*(20+abs(t_ptr->p1))) < 10*(tmp-abs(t_ptr->p1))) { msg_print("The door crashes open!"); invcopy(&t_list[c_ptr->tptr], OBJ_OPEN_DOOR); t_ptr->p1 = 1 - randint(2); /* 50% chance of breaking door */ c_ptr->fval = CORR_FLOOR; if (py.flags.confused == 0) move_char(dir, FALSE); else lite_spot(y, x); } else if (randint(150) > py.stats.use_stat[A_DEX]) { msg_print("You are off-balance."); py.flags.paralysis = 1 + randint(2); } else if (command_count == 0) msg_print("The door holds firm."); } else if (t_ptr->tval == TV_CHEST) { if (randint(10) == 1) { msg_print("You have destroyed the chest."); msg_print("and its contents!"); t_ptr->index = OBJ_RUINED_CHEST; t_ptr->flags = 0; } else if ((CH_LOCKED & t_ptr->flags) && (randint(10) == 1)) { msg_print("The lock breaks open!"); t_ptr->flags &= ~CH_LOCKED; } else count_msg_print("The chest holds firm."); } else /* Can't give free turn, or else player could try directions until he found invisible creature */ msg_print("You bash it, but nothing interesting happens."); } else { if (c_ptr->fval < MIN_CAVE_WALL) msg_print("You bash at empty space."); else /* same message for wall as for secret door */ msg_print("You bash it, but nothing interesting happens."); } } } moria-5.6.debian.1/source/moria3.c0000644000175000017500000007700311074756544015045 0ustar pjbpjb/* source/moria3.c: misc code, mainly to handle player commands Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #ifdef USG #ifndef ATARIST_MWC #include #endif #else #include #endif #if defined(LINT_ARGS) static void hit_trap(int, int); static void carry(int, int, int); static int summon_object(int, int, int, int); #endif /* Player hit a trap. (Chuckle) -RAK- */ static void hit_trap(y, x) int y, x; { int i, ty, tx, num, dam; register cave_type *c_ptr; register struct misc *p_ptr; register inven_type *t_ptr; bigvtype tmp; end_find(); change_trap(y, x); c_ptr = &cave[y][x]; p_ptr = &py.misc; t_ptr = &t_list[c_ptr->tptr]; dam = pdamroll(t_ptr->damage); switch(t_ptr->subval) { case 1: /* Open pit*/ msg_print("You fell into a pit!"); if (py.flags.ffall) msg_print("You gently float down."); else { objdes(tmp, t_ptr, TRUE); take_hit(dam, tmp); } break; case 2: /* Arrow trap*/ if (test_hit(125, 0, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) { objdes(tmp, t_ptr, TRUE); take_hit(dam, tmp); msg_print("An arrow hits you."); } else msg_print("An arrow barely misses you."); break; case 3: /* Covered pit*/ msg_print("You fell into a covered pit."); if (py.flags.ffall) msg_print("You gently float down."); else { objdes(tmp, t_ptr, TRUE); take_hit(dam, tmp); } place_trap(y, x, 0); break; case 4: /* Trap door*/ msg_print("You fell through a trap door!"); new_level_flag = TRUE; dun_level++; if (py.flags.ffall) msg_print("You gently float down."); else { objdes(tmp, t_ptr, TRUE); take_hit(dam, tmp); } /* Force the messages to display before starting to generate the next level. */ msg_print (CNIL); break; case 5: /* Sleep gas*/ if (py.flags.paralysis == 0) { msg_print("A strange white mist surrounds you!"); if (py.flags.free_act) msg_print("You are unaffected."); else { msg_print("You fall asleep."); py.flags.paralysis += randint(10) + 4; } } break; case 6: /* Hid Obj*/ (void) delete_object(y, x); place_object(y, x, FALSE); msg_print("Hmmm, there was something under this rock."); break; case 7: /* STR Dart*/ if (test_hit(125, 0, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) { if (!py.flags.sustain_str) { (void) dec_stat(A_STR); objdes(tmp, t_ptr, TRUE); take_hit(dam, tmp); msg_print("A small dart weakens you!"); } else msg_print("A small dart hits you."); } else msg_print("A small dart barely misses you."); break; case 8: /* Teleport*/ teleport_flag = TRUE; msg_print("You hit a teleport trap!"); /* Light up the teleport trap, before we teleport away. */ move_light (y, x, y, x); break; case 9: /* Rockfall*/ take_hit(dam, "a falling rock"); (void) delete_object(y, x); place_rubble(y, x); msg_print("You are hit by falling rock."); break; case 10: /* Corrode gas*/ /* Makes more sense to print the message first, then damage an object. */ msg_print("A strange red gas surrounds you."); corrode_gas("corrosion gas"); break; case 11: /* Summon mon*/ (void) delete_object(y, x); /* Rune disappears. */ num = 2 + randint (3); for (i = 0; i < num; i++) { ty = y; tx = x; (void) summon_monster(&ty, &tx, FALSE); } break; case 12: /* Fire trap*/ msg_print("You are enveloped in flames!"); fire_dam(dam, "a fire trap"); break; case 13: /* Acid trap*/ msg_print("You are splashed with acid!"); acid_dam(dam, "an acid trap"); break; case 14: /* Poison gas*/ msg_print("A pungent green gas surrounds you!"); poison_gas(dam, "a poison gas trap"); break; case 15: /* Blind Gas */ msg_print("A black gas surrounds you!"); py.flags.blind += randint(50) + 50; break; case 16: /* Confuse Gas*/ msg_print("A gas of scintillating colors surrounds you!"); py.flags.confused += randint(15) + 15; break; case 17: /* Slow Dart*/ if (test_hit(125, 0, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) { objdes(tmp, t_ptr, TRUE); take_hit(dam, tmp); msg_print("A small dart hits you!"); if (py.flags.free_act) msg_print("You are unaffected."); else py.flags.slow += randint(20) + 10; } else msg_print("A small dart barely misses you."); break; case 18: /* CON Dart*/ if (test_hit(125, 0, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) { if (!py.flags.sustain_con) { (void) dec_stat(A_CON); objdes(tmp, t_ptr, TRUE); take_hit(dam, tmp); msg_print("A small dart saps your health!"); } else msg_print("A small dart hits you."); } else msg_print("A small dart barely misses you."); break; case 19: /*Secret Door*/ break; case 99: /* Scare Mon*/ break; /* Town level traps are special, the stores. */ case 101: /* General */ enter_store(0); break; case 102: /* Armory */ enter_store(1); break; case 103: /* Weaponsmith*/ enter_store(2); break; case 104: /* Temple */ enter_store(3); break; case 105: /* Alchemy */ enter_store(4); break; case 106: /* Magic-User */ enter_store(5); break; default: msg_print("Unknown trap value."); break; } } /* Return spell number and failure chance -RAK- */ /* returns -1 if no spells in book returns 1 if choose a spell in book to cast returns 0 if don't choose a spell, i.e. exit with an escape */ int cast_spell(prompt, item_val, sn, sc) char *prompt; int item_val; int *sn, *sc; { int32u j; register int i, k; int spell[31], result, first_spell; register spell_type *s_ptr; result = -1; i = 0; j = inventory[item_val].flags; first_spell = bit_pos(&j); /* set j again, since bit_pos modified it */ j = inventory[item_val].flags & spell_learned; s_ptr = magic_spell[py.misc.pclass-1]; while (j) { k = bit_pos(&j); if (s_ptr[k].slevel <= py.misc.lev) { spell[i] = k; i++; } } if (i > 0) { result = get_spell(spell, i, sn, sc, prompt, first_spell); if (result && magic_spell[py.misc.pclass-1][*sn].smana > py.misc.cmana) { if (class[py.misc.pclass].spell == MAGE) result = get_check("You summon your limited strength to cast \ this one! Confirm?"); else result = get_check("The gods may think you presumptuous for \ this! Confirm?"); } } return(result); } /* Player is on an object. Many things can happen based -RAK- */ /* on the TVAL of the object. Traps are set off, money and most */ /* objects are picked up. Some objects, such as open doors, just*/ /* sit there. */ static void carry(y, x, pickup) int y, x; int pickup; { register int locn, i; bigvtype out_val, tmp_str; register cave_type *c_ptr; register inven_type *i_ptr; c_ptr = &cave[y][x]; i_ptr = &t_list[c_ptr->tptr]; i = t_list[c_ptr->tptr].tval; if (i <= TV_MAX_PICK_UP) { end_find(); /* There's GOLD in them thar hills! */ if (i == TV_GOLD) { py.misc.au += i_ptr->cost; objdes(tmp_str, i_ptr, TRUE); (void) sprintf(out_val, "You have found %ld gold pieces worth of %s", i_ptr->cost, tmp_str); prt_gold(); (void) delete_object(y, x); msg_print(out_val); } else { if (inven_check_num(i_ptr)) /* Too many objects? */ { /* Okay, pick it up */ if (pickup && prompt_carry_flag) { objdes(tmp_str, i_ptr, TRUE); /* change the period to a question mark */ tmp_str[strlen(tmp_str)-1] = '?'; (void) sprintf(out_val, "Pick up %s", tmp_str); pickup = get_check(out_val); } /* Check to see if it will change the players speed. */ if (pickup && !inven_check_weight(i_ptr)) { objdes(tmp_str, i_ptr, TRUE); /* change the period to a question mark */ tmp_str[strlen(tmp_str)-1] = '?'; (void) sprintf(out_val, "Exceed your weight limit to pick up %s", tmp_str); pickup = get_check(out_val); } /* Attempt to pick up an object. */ if (pickup) { locn = inven_carry(i_ptr); objdes(tmp_str, &inventory[locn], TRUE); (void) sprintf(out_val, "You have %s (%c)",tmp_str,locn+'a'); msg_print(out_val); (void) delete_object(y, x); } } else { objdes(tmp_str, i_ptr, TRUE); (void) sprintf(out_val, "You can't carry %s", tmp_str); msg_print(out_val); } } } /* OPPS! */ else if (i == TV_INVIS_TRAP || i == TV_VIS_TRAP || i == TV_STORE_DOOR) hit_trap(y, x); } /* Deletes a monster entry from the level -RAK- */ void delete_monster(j) int j; { register monster_type *m_ptr; m_ptr = &m_list[j]; cave[m_ptr->fy][m_ptr->fx].cptr = 0; if (m_ptr->ml) lite_spot((int)m_ptr->fy, (int)m_ptr->fx); if (j != mfptr - 1) { m_ptr = &m_list[mfptr - 1]; cave[m_ptr->fy][m_ptr->fx].cptr = j; m_list[j] = m_list[mfptr - 1]; } mfptr--; m_list[mfptr] = blank_monster; if (mon_tot_mult > 0) mon_tot_mult--; } /* The following two procedures implement the same function as delete monster. However, they are used within creatures(), because deleting a monster while scanning the m_list causes two problems, monsters might get two turns, and m_ptr/monptr might be invalid after the delete_monster. Hence the delete is done in two steps. */ /* fix1_delete_monster does everything delete_monster does except delete the monster record and reduce mfptr, this is called in breathe, and a couple of places in creatures.c */ void fix1_delete_monster(j) int j; { register monster_type *m_ptr; m_ptr = &m_list[j]; /* force the hp negative to ensure that the monster is dead, for example, if the monster was just eaten by another, it will still have positive hit points */ m_ptr->hp = -1; cave[m_ptr->fy][m_ptr->fx].cptr = 0; if (m_ptr->ml) lite_spot((int)m_ptr->fy, (int)m_ptr->fx); if (mon_tot_mult > 0) mon_tot_mult--; } /* fix2_delete_monster does everything in delete_monster that wasn't done by fix1_monster_delete above, this is only called in creatures() */ void fix2_delete_monster(j) int j; { register monster_type *m_ptr; if (j != mfptr - 1) { m_ptr = &m_list[mfptr - 1]; cave[m_ptr->fy][m_ptr->fx].cptr = j; m_list[j] = m_list[mfptr - 1]; } m_list[mfptr - 1] = blank_monster; mfptr--; } /* Creates objects nearby the coordinates given -RAK- */ static int summon_object(y, x, num, typ) int y, x, num, typ; { register int i, j, k; register cave_type *c_ptr; int real_typ, res; if ((typ == 1) || (typ == 5)) real_typ = 1; /* typ == 1 -> objects */ else real_typ = 256; /* typ == 2 -> gold */ res = 0; do { i = 0; do { j = y - 3 + randint(5); k = x - 3 + randint(5); if (in_bounds(j, k) && los(y, x, j, k)) { c_ptr = &cave[j][k]; if (c_ptr->fval <= MAX_OPEN_SPACE && (c_ptr->tptr == 0)) { if ((typ == 3) || (typ == 7)) /* typ == 3 -> 50% objects, 50% gold */ { if (randint(100) < 50) real_typ = 1; else real_typ = 256; } if (real_typ == 1) place_object(j, k, (typ >= 4)); else place_gold(j, k); lite_spot(j, k); if (test_light(j, k)) res += real_typ; i = 20; } } i++; } while (i <= 20); num--; } while (num != 0); return res; } /* Deletes object from given location -RAK- */ int delete_object(y, x) int y, x; { register int delete; register cave_type *c_ptr; c_ptr = &cave[y][x]; if (c_ptr->fval == BLOCKED_FLOOR) c_ptr->fval = CORR_FLOOR; pusht(c_ptr->tptr); c_ptr->tptr = 0; c_ptr->fm = FALSE; lite_spot(y, x); if (test_light(y, x)) delete = TRUE; else delete = FALSE; return(delete); } /* Allocates objects upon a creatures death -RAK- */ /* Oh well, another creature bites the dust. Reward the victor*/ /* based on flags set in the main creature record */ /* Returns a mask of bits from the given flags which indicates what the monster is seen to have dropped. This may be added to monster memory. */ int32u monster_death(y, x, flags) int y, x; register int32u flags; { register int i, number; int32u dump, res; #if defined(ATARIST_MWC) int32u holder; /* avoid a compiler bug */ #endif #if !defined(ATARIST_MWC) if (flags & CM_CARRY_OBJ) i = 1; else i = 0; if (flags & CM_CARRY_GOLD) i += 2; if (flags & CM_SMALL_OBJ) i += 4; number = 0; if ((flags & CM_60_RANDOM) && (randint(100) < 60)) number++; if ((flags & CM_90_RANDOM) && (randint(100) < 90)) number++; if (flags & CM_1D2_OBJ) number += randint(2); if (flags & CM_2D2_OBJ) number += damroll(2, 2); if (flags & CM_4D2_OBJ) number += damroll(4, 2); if (number > 0) dump = summon_object(y, x, number, i); else dump = 0; #else holder = CM_CARRY_OBJ; if (flags & holder) i = 1; else i = 0; holder = CM_CARRY_GOLD; if (flags & holder) i += 2; holder = CM_SMALL_OBJ; if (flags & holder) i += 4; number = 0; holder = CM_60_RANDOM; if ((flags & holder) && (randint(100) < 60)) number++; holder = CM_90_RANDOM; if ((flags & holder) && (randint(100) < 90)) number++; holder = CM_1D2_OBJ; if (flags & holder) number += randint(2); holder = CM_2D2_OBJ; if (flags & holder) number += damroll(2, 2); holder = CM_4D2_OBJ; if (flags & holder) number += damroll(4, 2); if (number > 0) dump = summon_object(y, x, number, i); else dump = 0; #endif #if defined(ATARIST_MWC) holder = CM_WIN; if (flags & holder) #else if (flags & CM_WIN) #endif if (!death) /* maybe the player died in mid-turn */ { total_winner = TRUE; prt_winner(); msg_print("*** CONGRATULATIONS *** You have won the game."); msg_print("You cannot save this game, but you may retire when ready."); } if (dump) { res = 0; if (dump & 255) #ifdef ATARIST_MWC { holder = CM_CARRY_OBJ; if (i & 0x04) holder = CM_CARRY_OBJ|CM_SMALL_OBJ; res |= holder; } #else { res |= CM_CARRY_OBJ; if (i & 0x04) res |= CM_SMALL_OBJ; } #endif if (dump >= 256) #ifdef ATARIST_MWC { holder = CM_CARRY_GOLD; res |= holder; } #else res |= CM_CARRY_GOLD; #endif dump = (dump % 256) + (dump / 256); /* number of items */ res |= dump << CM_TR_SHIFT; } else res = 0; return res; } /* Decreases monsters hit points and deletes monster if needed. */ /* (Picking on my babies.) -RAK- */ int mon_take_hit(monptr, dam) int monptr, dam; { register int32u i; int32 new_exp, new_exp_frac; register monster_type *m_ptr; register struct misc *p_ptr; register creature_type *c_ptr; int m_take_hit; int32u tmp; #ifdef ATARIST_MWC int32u holder; #endif m_ptr = &m_list[monptr]; m_ptr->hp -= dam; m_ptr->csleep = 0; if (m_ptr->hp < 0) { i = monster_death((int)m_ptr->fy, (int)m_ptr->fx, c_list[m_ptr->mptr].cmove); if ((py.flags.blind < 1 && m_ptr->ml) #ifdef ATARIST_MWC || (c_list[m_ptr->mptr].cmove & (holder = CM_WIN))) #else || (c_list[m_ptr->mptr].cmove & CM_WIN)) #endif { #ifdef ATARIST_MWC holder = CM_TREASURE; tmp = (c_recall[m_ptr->mptr].r_cmove & holder) >> CM_TR_SHIFT; if (tmp > ((i & holder) >> CM_TR_SHIFT)) i = (i & ~holder) | (tmp << CM_TR_SHIFT); c_recall[m_ptr->mptr].r_cmove = (c_recall[m_ptr->mptr].r_cmove & ~holder) | i; #else tmp = (c_recall[m_ptr->mptr].r_cmove & CM_TREASURE) >> CM_TR_SHIFT; if (tmp > ((i & CM_TREASURE) >> CM_TR_SHIFT)) i = (i & ~CM_TREASURE) | (tmp << CM_TR_SHIFT); c_recall[m_ptr->mptr].r_cmove = (c_recall[m_ptr->mptr].r_cmove & ~CM_TREASURE) | i; #endif if (c_recall[m_ptr->mptr].r_kills < MAX_SHORT) c_recall[m_ptr->mptr].r_kills++; } c_ptr = &c_list[m_ptr->mptr]; p_ptr = &py.misc; new_exp = ((long)c_ptr->mexp * c_ptr->level) / p_ptr->lev; new_exp_frac = ((((long)c_ptr->mexp * c_ptr->level) % p_ptr->lev) * 0x10000L / p_ptr->lev) + p_ptr->exp_frac; if (new_exp_frac >= 0x10000L) { new_exp++; p_ptr->exp_frac = new_exp_frac - 0x10000L; } else p_ptr->exp_frac = new_exp_frac; p_ptr->exp += new_exp; /* can't call prt_experience() here, as that would result in "new level" message appearing before "monster dies" message */ m_take_hit = m_ptr->mptr; /* in case this is called from within creatures(), this is a horrible hack, the m_list/creatures() code needs to be rewritten */ if (hack_monptr < monptr) delete_monster(monptr); else fix1_delete_monster(monptr); } else m_take_hit = -1; return(m_take_hit); } /* Player attacks a (poor, defenseless) creature -RAK- */ void py_attack(y, x) int y, x; { register int k, blows; int crptr, monptr, tot_tohit, base_tohit; vtype m_name, out_val; register inven_type *i_ptr; register struct misc *p_ptr; #ifdef ATARIST_MWC int32u holder; #endif crptr = cave[y][x].cptr; monptr = m_list[crptr].mptr; m_list[crptr].csleep = 0; i_ptr = &inventory[INVEN_WIELD]; /* Does the player know what he's fighting? */ if (!m_list[crptr].ml) (void) strcpy(m_name, "it"); else (void) sprintf(m_name, "the %s", c_list[monptr].name); if (i_ptr->tval != TV_NOTHING) /* Proper weapon */ blows = attack_blows((int)i_ptr->weight, &tot_tohit); else /* Bare hands? */ { blows = 2; tot_tohit = -3; } if ((i_ptr->tval >= TV_SLING_AMMO) && (i_ptr->tval <= TV_SPIKE)) /* Fix for arrows */ blows = 1; p_ptr = &py.misc; tot_tohit += p_ptr->ptohit; /* if creature not lit, make it more difficult to hit */ if (m_list[crptr].ml) base_tohit = p_ptr->bth; else base_tohit = (p_ptr->bth / 2) - (tot_tohit * (BTH_PLUS_ADJ-1)) - (p_ptr->lev * class_level_adj[p_ptr->pclass][CLA_BTH] / 2); /* Loop for number of blows, trying to hit the critter. */ do { if (test_hit(base_tohit, (int)p_ptr->lev, tot_tohit, (int)c_list[monptr].ac, CLA_BTH)) { (void) sprintf(out_val, "You hit %s.", m_name); msg_print(out_val); if (i_ptr->tval != TV_NOTHING) { k = pdamroll(i_ptr->damage); k = tot_dam(i_ptr, k, monptr); k = critical_blow((int)i_ptr->weight, tot_tohit, k, CLA_BTH); } else /* Bare hands!? */ { k = damroll(1, 1); k = critical_blow(1, 0, k, CLA_BTH); } k += p_ptr->ptodam; if (k < 0) k = 0; if (py.flags.confuse_monster) { py.flags.confuse_monster = FALSE; msg_print("Your hands stop glowing."); if ((c_list[monptr].cdefense & CD_NO_SLEEP) || (randint(MAX_MONS_LEVEL) < c_list[monptr].level)) (void) sprintf(out_val, "%s is unaffected.", m_name); else { (void) sprintf(out_val, "%s appears confused.", m_name); if (m_list[crptr].confused) m_list[crptr].confused += 3; else m_list[crptr].confused = 2 + randint(16); } msg_print(out_val); if (m_list[crptr].ml && randint(4) == 1) c_recall[monptr].r_cdefense |= c_list[monptr].cdefense & CD_NO_SLEEP; } /* See if we done it in. */ if (mon_take_hit(crptr, k) >= 0) { (void) sprintf(out_val, "You have slain %s.", m_name); msg_print(out_val); prt_experience(); blows = 0; } if ((i_ptr->tval >= TV_SLING_AMMO) && (i_ptr->tval <= TV_SPIKE)) /* Use missiles up*/ { i_ptr->number--; inven_weight -= i_ptr->weight; #ifdef ATARIST_MWC py.flags.status |= (holder = PY_STR_WGT); #else py.flags.status |= PY_STR_WGT; #endif if (i_ptr->number == 0) { equip_ctr--; py_bonuses(i_ptr, -1); invcopy(i_ptr, OBJ_NOTHING); calc_bonuses(); } } } else { (void) sprintf(out_val, "You miss %s.", m_name); msg_print(out_val); } blows--; } while (blows >= 1); } /* Moves player from one space to another. -RAK- */ /* Note: This routine has been pre-declared; see that for argument*/ void move_char(dir, do_pickup) int dir, do_pickup; { int old_row, old_col, old_find_flag; int y, x; register int i, j; register cave_type *c_ptr, *d_ptr; if ((py.flags.confused > 0) && /* Confused? */ (randint(4) > 1) && /* 75% random movement */ (dir != 5)) /* Never random if sitting*/ { dir = randint(9); end_find(); } y = char_row; x = char_col; if (mmove(dir, &y, &x)) /* Legal move? */ { c_ptr = &cave[y][x]; /* if there is no creature, or an unlit creature in the walls then... */ /* disallow attacks against unlit creatures in walls because moving into a wall is a free turn normally, hence don't give player free turns attacking each wall in an attempt to locate the invisible creature, instead force player to tunnel into walls which always takes a turn */ if ((c_ptr->cptr < 2) || (!m_list[c_ptr->cptr].ml && c_ptr->fval >= MIN_CLOSED_SPACE)) { if (c_ptr->fval <= MAX_OPEN_SPACE) /* Open floor spot */ { /* Make final assignments of char co-ords */ old_row = char_row; old_col = char_col; char_row = y; char_col = x; /* Move character record (-1) */ move_rec(old_row, old_col, char_row, char_col); /* Check for new panel */ if (get_panel(char_row, char_col, FALSE)) prt_map(); /* Check to see if he should stop */ if (find_flag) area_affect(dir, char_row, char_col); /* Check to see if he notices something */ /* fos may be negative if have good rings of searching */ if ((py.misc.fos <= 1) || (randint(py.misc.fos) == 1) || (py.flags.status & PY_SEARCH)) search(char_row, char_col, py.misc.srh); /* A room of light should be lit. */ if (c_ptr->fval == LIGHT_FLOOR) { if (!c_ptr->pl && !py.flags.blind) light_room(char_row, char_col); } /* In doorway of light-room? */ else if (c_ptr->lr && (py.flags.blind < 1)) for (i = (char_row - 1); i <= (char_row + 1); i++) for (j = (char_col - 1); j <= (char_col + 1); j++) { d_ptr = &cave[i][j]; if ((d_ptr->fval == LIGHT_FLOOR) && (!d_ptr->pl)) light_room(i, j); } /* Move the light source */ move_light(old_row, old_col, char_row, char_col); /* An object is beneath him. */ if (c_ptr->tptr != 0) { carry(char_row, char_col, do_pickup); /* if stepped on falling rock trap, and space contains rubble, then step back into a clear area */ if (t_list[c_ptr->tptr].tval == TV_RUBBLE) { move_rec(char_row, char_col, old_row, old_col); move_light(char_row, char_col, old_row, old_col); char_row = old_row; char_col = old_col; /* check to see if we have stepped back onto another trap, if so, set it off */ c_ptr = &cave[char_row][char_col]; if (c_ptr->tptr != 0) { i = t_list[c_ptr->tptr].tval; if (i == TV_INVIS_TRAP || i == TV_VIS_TRAP || i == TV_STORE_DOOR) hit_trap(char_row, char_col); } } } } else /*Can't move onto floor space*/ { if (!find_flag && (c_ptr->tptr != 0)) { if (t_list[c_ptr->tptr].tval == TV_RUBBLE) msg_print("There is rubble blocking your way."); else if (t_list[c_ptr->tptr].tval == TV_CLOSED_DOOR) msg_print("There is a closed door blocking your way."); } else end_find(); free_turn_flag = TRUE; } } else /* Attacking a creature! */ { old_find_flag = find_flag; end_find(); /* if player can see monster, and was in find mode, then nothing */ if (m_list[c_ptr->cptr].ml && old_find_flag) { /* did not do anything this turn */ free_turn_flag = TRUE; } else { if (py.flags.afraid < 1) /* Coward? */ py_attack(y, x); else /* Coward! */ msg_print("You are too afraid!"); } } } } /* Chests have traps too. -RAK- */ /* Note: Chest traps are based on the FLAGS value */ void chest_trap(y, x) int y, x; { register int i; int j, k; register inven_type *t_ptr; t_ptr = &t_list[cave[y][x].tptr]; if (CH_LOSE_STR & t_ptr->flags) { msg_print("A small needle has pricked you!"); if (!py.flags.sustain_str) { (void) dec_stat(A_STR); take_hit(damroll(1, 4), "a poison needle"); msg_print("You feel weakened!"); } else msg_print("You are unaffected."); } if (CH_POISON & t_ptr->flags) { msg_print("A small needle has pricked you!"); take_hit(damroll(1, 6), "a poison needle"); py.flags.poisoned += 10 + randint(20); } if (CH_PARALYSED & t_ptr->flags) { msg_print("A puff of yellow gas surrounds you!"); if (py.flags.free_act) msg_print("You are unaffected."); else { msg_print("You choke and pass out."); py.flags.paralysis = 10 + randint(20); } } if (CH_SUMMON & t_ptr->flags) { for (i = 0; i < 3; i++) { j = y; k = x; (void) summon_monster(&j, &k, FALSE); } } if (CH_EXPLODE & t_ptr->flags) { msg_print("There is a sudden explosion!"); (void) delete_object(y, x); take_hit(damroll(5, 8), "an exploding chest"); } } /* Opens a closed door or closed chest. -RAK- */ void openobject() { int y, x, i, dir; int flag, no_object; register cave_type *c_ptr; register inven_type *t_ptr; register struct misc *p_ptr; register monster_type *m_ptr; vtype m_name, out_val; #ifdef ATARIST_MWC int32u holder; #endif y = char_row; x = char_col; if (get_dir(CNIL, &dir)) { (void) mmove(dir, &y, &x); c_ptr = &cave[y][x]; no_object = FALSE; if (c_ptr->cptr > 1 && c_ptr->tptr != 0 && (t_list[c_ptr->tptr].tval == TV_CLOSED_DOOR || t_list[c_ptr->tptr].tval == TV_CHEST)) { m_ptr = &m_list[c_ptr->cptr]; if (m_ptr->ml) (void) sprintf (m_name, "The %s", c_list[m_ptr->mptr].name); else (void) strcpy (m_name, "Something"); (void) sprintf(out_val, "%s is in your way!", m_name); msg_print(out_val); } else if (c_ptr->tptr != 0) /* Closed door */ if (t_list[c_ptr->tptr].tval == TV_CLOSED_DOOR) { t_ptr = &t_list[c_ptr->tptr]; if (t_ptr->p1 > 0) /* It's locked. */ { p_ptr = &py.misc; i = p_ptr->disarm + 2*todis_adj() + stat_adj(A_INT) + (class_level_adj[p_ptr->pclass][CLA_DISARM] * p_ptr->lev / 3); if (py.flags.confused > 0) msg_print("You are too confused to pick the lock."); else if ((i-t_ptr->p1) > randint(100)) { msg_print("You have picked the lock."); py.misc.exp++; prt_experience(); t_ptr->p1 = 0; } else count_msg_print("You failed to pick the lock."); } else if (t_ptr->p1 < 0) /* It's stuck */ msg_print("It appears to be stuck."); if (t_ptr->p1 == 0) { invcopy(&t_list[c_ptr->tptr], OBJ_OPEN_DOOR); c_ptr->fval = CORR_FLOOR; lite_spot(y, x); command_count = 0; } } /* Open a closed chest. */ else if (t_list[c_ptr->tptr].tval == TV_CHEST) { p_ptr = &py.misc; i = p_ptr->disarm + 2*todis_adj() + stat_adj(A_INT) + (class_level_adj[p_ptr->pclass][CLA_DISARM] * p_ptr->lev / 3); t_ptr = &t_list[c_ptr->tptr]; flag = FALSE; if (CH_LOCKED & t_ptr->flags) if (py.flags.confused > 0) msg_print("You are too confused to pick the lock."); else if ((i-(int)t_ptr->level) > randint(100)) { msg_print("You have picked the lock."); flag = TRUE; py.misc.exp += t_ptr->level; prt_experience(); } else count_msg_print("You failed to pick the lock."); else flag = TRUE; if (flag) { t_ptr->flags &= ~CH_LOCKED; t_ptr->name2 = SN_EMPTY; known2(t_ptr); t_ptr->cost = 0; } flag = FALSE; /* Was chest still trapped? (Snicker) */ if ((CH_LOCKED & t_ptr->flags) == 0) { chest_trap(y, x); if (c_ptr->tptr != 0) flag = TRUE; } /* Chest treasure is allocated as if a creature */ /* had been killed. */ if (flag) { /* clear the cursed chest/monster win flag, so that people can not win by opening a cursed chest */ #ifdef ATARIST_MWC t_list[c_ptr->tptr].flags &= ~(holder = TR_CURSED); #else t_list[c_ptr->tptr].flags &= ~TR_CURSED; #endif (void) monster_death(y, x, t_list[c_ptr->tptr].flags); t_list[c_ptr->tptr].flags = 0; } } else no_object = TRUE; else no_object = TRUE; if (no_object) { msg_print("I do not see anything you can open there."); free_turn_flag = TRUE; } } } /* Closes an open door. -RAK- */ void closeobject() { int y, x, dir, no_object; vtype out_val, m_name; register cave_type *c_ptr; register monster_type *m_ptr; y = char_row; x = char_col; if (get_dir(CNIL, &dir)) { (void) mmove(dir, &y, &x); c_ptr = &cave[y][x]; no_object = FALSE; if (c_ptr->tptr != 0) if (t_list[c_ptr->tptr].tval == TV_OPEN_DOOR) if (c_ptr->cptr == 0) if (t_list[c_ptr->tptr].p1 == 0) { invcopy(&t_list[c_ptr->tptr], OBJ_CLOSED_DOOR); c_ptr->fval = BLOCKED_FLOOR; lite_spot(y, x); } else msg_print("The door appears to be broken."); else { m_ptr = &m_list[c_ptr->cptr]; if (m_ptr->ml) (void) sprintf (m_name, "The %s", c_list[m_ptr->mptr].name); else (void) strcpy (m_name, "Something"); (void) sprintf(out_val, "%s is in your way!", m_name); msg_print(out_val); } else no_object = TRUE; else no_object = TRUE; if (no_object) { msg_print("I do not see anything you can close there."); free_turn_flag = TRUE; } } } /* Tunneling through real wall: 10, 11, 12 -RAK- */ /* Used by TUNNEL and WALL_TO_MUD */ int twall(y, x, t1, t2) int y, x, t1, t2; { register int i, j; register cave_type *c_ptr; int res, found; res = FALSE; if (t1 > t2) { c_ptr = &cave[y][x]; if (c_ptr->lr) { /* should become a room space, check to see whether it should be LIGHT_FLOOR or DARK_FLOOR */ found = FALSE; for (i = y-1; i <= y+1; i++) for (j = x-1; j <= x+1; j++) if (cave[i][j].fval <= MAX_CAVE_ROOM) { c_ptr->fval = cave[i][j].fval; c_ptr->pl = cave[i][j].pl; found = TRUE; break; } if (!found) { c_ptr->fval = CORR_FLOOR; c_ptr->pl = FALSE; } } else { /* should become a corridor space */ c_ptr->fval = CORR_FLOOR; c_ptr->pl = FALSE; } c_ptr->fm = FALSE; if (panel_contains(y, x)) if ((c_ptr->tl || c_ptr->pl) && c_ptr->tptr != 0) msg_print("You have found something!"); lite_spot(y, x); res = TRUE; } return(res); } moria-5.6.debian.1/source/creature.c0000644000175000017500000013411611074756544015464 0ustar pjbpjb/* source/creature.c: handle monster movement and attacks Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include #include #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #ifdef USG #ifndef ATARIST_MWC #include #else char *strcat(); char *strcpy(); #endif #else #include #endif #if defined(LINT_ARGS) static int movement_rate(int16); static int check_mon_lite(int, int); static void get_moves(int, int *); static void make_attack(int); static void make_move(int, int *, int32u *); static void mon_cast_spell(int, int *); static void mon_move(int, int32u *); #endif #ifdef ATARIST_TC /* Include this to get prototypes for standard library functions. */ #include #endif /* Updates screen when monsters move about -RAK- */ void update_mon(monptr) int monptr; { register int flag; register cave_type *c_ptr; register monster_type *m_ptr; register creature_type *r_ptr; #ifdef ATARIST_MWC int32u holder; #endif m_ptr = &m_list[monptr]; flag = FALSE; if ((m_ptr->cdis <= MAX_SIGHT) && !(py.flags.status & PY_BLIND) && (panel_contains((int)m_ptr->fy, (int)m_ptr->fx))) { /* Wizard sight. */ if (wizard) flag = TRUE; /* Normal sight. */ else if (los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx)) { c_ptr = &cave[m_ptr->fy][m_ptr->fx]; r_ptr = &c_list[m_ptr->mptr]; if (c_ptr->pl || c_ptr->tl || (find_flag && m_ptr->cdis < 2 && player_light)) { #ifdef ATARIST_MWC holder = CM_INVISIBLE; if ((holder & r_ptr->cmove) == 0) #else if ((CM_INVISIBLE & r_ptr->cmove) == 0) #endif flag = TRUE; else if (py.flags.see_inv) { flag = TRUE; #ifdef ATARIST_MWC c_recall[m_ptr->mptr].r_cmove |= holder; #else c_recall[m_ptr->mptr].r_cmove |= CM_INVISIBLE; #endif } } /* Infra vision. */ else if ((py.flags.see_infra > 0) && (m_ptr->cdis <= py.flags.see_infra) && (CD_INFRA & r_ptr->cdefense)) { flag = TRUE; c_recall[m_ptr->mptr].r_cdefense |= CD_INFRA; } } } /* Light it up. */ if (flag) { if (!m_ptr->ml) { disturb (1, 0); m_ptr->ml = TRUE; lite_spot((int)m_ptr->fy, (int)m_ptr->fx); screen_change = TRUE; /* notify inven_command */ } } /* Turn it off. */ else if (m_ptr->ml) { m_ptr->ml = FALSE; lite_spot((int)m_ptr->fy, (int)m_ptr->fx); screen_change = TRUE; /* notify inven_command */ } } /* Given speed, returns number of moves this turn. -RAK- */ /* NOTE: Player must always move at least once per iteration, */ /* a slowed player is handled by moving monsters faster */ static int movement_rate(speed) register int16 speed; { if (speed > 0) { if (py.flags.rest != 0) return 1; else return speed; } else { /* speed must be negative here */ return ((turn % (2 - speed)) == 0); } } /* Makes sure a new creature gets lit up. -CJS- */ static int check_mon_lite(y, x) int y, x; { register int monptr; monptr = cave[y][x].cptr; if (monptr <= 1) return FALSE; else { update_mon(monptr); return m_list[monptr].ml; } } /* Choose correct directions for monster movement -RAK- */ static void get_moves(monptr, mm) int monptr; register int *mm; { int y, ay, x, ax, move_val; y = m_list[monptr].fy - char_row; x = m_list[monptr].fx - char_col; if (y < 0) { move_val = 8; ay = -y; } else { move_val = 0; ay = y; } if (x > 0) { move_val += 4; ax = x; } else ax = -x; /* this has the advantage of preventing the diamond maneuvre, also faster */ if (ay > (ax << 1)) move_val += 2; else if (ax > (ay << 1)) move_val++; switch(move_val) { case 0: mm[0] = 9; if (ay > ax) { mm[1] = 8; mm[2] = 6; mm[3] = 7; mm[4] = 3; } else { mm[1] = 6; mm[2] = 8; mm[3] = 3; mm[4] = 7; } break; case 1: case 9: mm[0] = 6; if (y < 0) { mm[1] = 3; mm[2] = 9; mm[3] = 2; mm[4] = 8; } else { mm[1] = 9; mm[2] = 3; mm[3] = 8; mm[4] = 2; } break; case 2: case 6: mm[0] = 8; if (x < 0) { mm[1] = 9; mm[2] = 7; mm[3] = 6; mm[4] = 4; } else { mm[1] = 7; mm[2] = 9; mm[3] = 4; mm[4] = 6; } break; case 4: mm[0] = 7; if (ay > ax) { mm[1] = 8; mm[2] = 4; mm[3] = 9; mm[4] = 1; } else { mm[1] = 4; mm[2] = 8; mm[3] = 1; mm[4] = 9; } break; case 5: case 13: mm[0] = 4; if (y < 0) { mm[1] = 1; mm[2] = 7; mm[3] = 2; mm[4] = 8; } else { mm[1] = 7; mm[2] = 1; mm[3] = 8; mm[4] = 2; } break; case 8: mm[0] = 3; if (ay > ax) { mm[1] = 2; mm[2] = 6; mm[3] = 1; mm[4] = 9; } else { mm[1] = 6; mm[2] = 2; mm[3] = 9; mm[4] = 1; } break; case 10: case 14: mm[0] = 2; if (x < 0) { mm[1] = 3; mm[2] = 1; mm[3] = 6; mm[4] = 4; } else { mm[1] = 1; mm[2] = 3; mm[3] = 4; mm[4] = 6; } break; case 12: mm[0] = 1; if (ay > ax) { mm[1] = 2; mm[2] = 4; mm[3] = 3; mm[4] = 7; } else { mm[1] = 4; mm[2] = 2; mm[3] = 7; mm[4] = 3; } break; } } /* Make an attack on the player (chuckle.) -RAK- */ static void make_attack(monptr) int monptr; { int attype, adesc, adice, asides; int i, j, damage, flag, attackn, notice, visible; int32 gold; int8u *attstr; vtype cdesc, tmp_str, ddesc; register creature_type *r_ptr; monster_type *m_ptr; register struct misc *p_ptr; register struct flags *f_ptr; register inven_type *i_ptr; #ifdef ATARIST_MWC int32u holder; #endif if (death) /* don't beat a dead body! */ return; m_ptr = &m_list[monptr]; r_ptr = &c_list[m_ptr->mptr]; if (!m_ptr->ml) (void) strcpy(cdesc, "It "); else (void) sprintf(cdesc, "The %s ", r_ptr->name); /* For "DIED_FROM" string */ #ifdef ATARIST_MWC holder = CM_WIN; if (holder & r_ptr->cmove) #else if (CM_WIN & r_ptr->cmove) #endif (void) sprintf(ddesc, "The %s", r_ptr->name); else if (is_a_vowel (r_ptr->name[0])) (void) sprintf(ddesc, "an %s", r_ptr->name); else (void) sprintf (ddesc, "a %s", r_ptr->name); /* End DIED_FROM */ attackn = 0; attstr = r_ptr->damage; while ((*attstr != 0) && !death) { attype = monster_attacks[*attstr].attack_type; adesc = monster_attacks[*attstr].attack_desc; adice = monster_attacks[*attstr].attack_dice; asides = monster_attacks[*attstr].attack_sides; attstr++; flag = FALSE; if ((py.flags.protevil > 0) && (r_ptr->cdefense & CD_EVIL) && ((py.misc.lev + 1) > r_ptr->level)) { if (m_ptr->ml) c_recall[m_ptr->mptr].r_cdefense |= CD_EVIL; attype = 99; adesc = 99; } p_ptr = &py.misc; switch(attype) { case 1: /*Normal attack */ if (test_hit(60, (int)r_ptr->level, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 2: /*Lose Strength*/ if (test_hit(-3, (int)r_ptr->level, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 3: /*Confusion attack*/ if (test_hit(10, (int)r_ptr->level, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 4: /*Fear attack */ if (test_hit(10, (int)r_ptr->level, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 5: /*Fire attack */ if (test_hit(10, (int)r_ptr->level, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 6: /*Acid attack */ if (test_hit(0, (int)r_ptr->level, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 7: /*Cold attack */ if (test_hit(10, (int)r_ptr->level, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 8: /*Lightning attack*/ if (test_hit(10, (int)r_ptr->level, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 9: /*Corrosion attack*/ if (test_hit(0, (int)r_ptr->level, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 10: /*Blindness attack*/ if (test_hit(2, (int)r_ptr->level, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 11: /*Paralysis attack*/ if (test_hit(2, (int)r_ptr->level, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 12: /*Steal Money */ if ((test_hit(5, (int)r_ptr->level, 0, (int)py.misc.lev, CLA_MISC_HIT)) && (py.misc.au > 0)) flag = TRUE; break; case 13: /*Steal Object */ if ((test_hit(2, (int)r_ptr->level, 0, (int)py.misc.lev, CLA_MISC_HIT)) && (inven_ctr > 0)) flag = TRUE; break; case 14: /*Poison */ if (test_hit(5, (int)r_ptr->level, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 15: /*Lose dexterity*/ if (test_hit(0, (int)r_ptr->level, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 16: /*Lose constitution*/ if (test_hit(0, (int)r_ptr->level, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 17: /*Lose intelligence*/ if (test_hit(2, (int)r_ptr->level, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 18: /*Lose wisdom*/ if (test_hit(2, (int)r_ptr->level, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 19: /*Lose experience*/ if (test_hit(5, (int)r_ptr->level, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 20: /*Aggravate monsters*/ flag = TRUE; break; case 21: /*Disenchant */ if (test_hit(20, (int)r_ptr->level, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 22: /*Eat food */ if (test_hit(5, (int)r_ptr->level, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 23: /*Eat light */ if (test_hit(5, (int)r_ptr->level, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 24: /*Eat charges */ if ((test_hit(15, (int)r_ptr->level, 0, p_ptr->pac+p_ptr->ptoac, CLA_MISC_HIT)) && (inven_ctr > 0)) /* check to make sure an object exists */ flag = TRUE; break; case 99: flag = TRUE; break; default: break; } if (flag) { /* can not strcat to cdesc because the creature may have multiple attacks */ disturb (1, 0); (void) strcpy(tmp_str, cdesc); switch(adesc) { case 1: msg_print(strcat(tmp_str, "hits you.")); break; case 2: msg_print(strcat(tmp_str, "bites you.")); break; case 3: msg_print(strcat(tmp_str, "claws you.")); break; case 4: msg_print(strcat(tmp_str, "stings you.")); break; case 5: msg_print(strcat(tmp_str, "touches you.")); break; #if 0 case 6: msg_print(strcat(tmp_str, "kicks you.")); break; #endif case 7: msg_print(strcat(tmp_str, "gazes at you.")); break; case 8: msg_print(strcat(tmp_str, "breathes on you.")); break; case 9: msg_print(strcat(tmp_str, "spits on you.")); break; case 10: msg_print(strcat(tmp_str,"makes a horrible wail."));break; #if 0 case 11: msg_print(strcat(tmp_str, "embraces you.")); break; #endif case 12: msg_print(strcat(tmp_str, "crawls on you.")); break; case 13: msg_print(strcat(tmp_str, "releases a cloud of spores.")); break; case 14: msg_print(strcat(tmp_str, "begs you for money.")); break; case 15: msg_print("You've been slimed!"); break; case 16: msg_print(strcat(tmp_str, "crushes you.")); break; case 17: msg_print(strcat(tmp_str, "tramples you.")); break; case 18: msg_print(strcat(tmp_str, "drools on you.")); break; case 19: switch(randint(9)) { case 1: msg_print(strcat(tmp_str, "insults you!")); break; case 2: msg_print(strcat(tmp_str, "insults your mother!")); break; case 3: msg_print(strcat(tmp_str, "gives you the finger!")); break; case 4: msg_print(strcat(tmp_str, "humiliates you!")); break; case 5: msg_print(strcat(tmp_str, "wets on your leg!")); break; case 6: msg_print(strcat(tmp_str, "defiles you!")); break; case 7: msg_print(strcat(tmp_str, "dances around you!"));break; case 8: msg_print(strcat(tmp_str, "makes obscene gestures!")); break; case 9: msg_print(strcat(tmp_str, "moons you!!!")); break; } break; case 99: msg_print(strcat(tmp_str, "is repelled.")); break; default: break; } notice = TRUE; /* always fail to notice attack if creature invisible, set notice and visible here since creature may be visible when attacking and then teleport afterwards (becoming effectively invisible) */ if (!m_ptr->ml) { visible = FALSE; notice = FALSE; } else visible = TRUE; damage = damroll (adice, asides); switch(attype) { case 1: /*Normal attack */ /* round half-way case down */ damage -= ((p_ptr->pac+p_ptr->ptoac) * damage) / 200; take_hit(damage, ddesc); break; case 2: /*Lose Strength*/ take_hit(damage, ddesc); if (py.flags.sustain_str) msg_print("You feel weaker for a moment, but it passes."); else if (randint(2) == 1) { msg_print("You feel weaker."); (void) dec_stat (A_STR); } else notice = FALSE; break; case 3: /*Confusion attack*/ f_ptr = &py.flags; take_hit(damage, ddesc); if (randint(2) == 1) { if (f_ptr->confused < 1) { msg_print("You feel confused."); f_ptr->confused += randint((int)r_ptr->level); } else notice = FALSE; f_ptr->confused += 3; } else notice = FALSE; break; case 4: /*Fear attack */ f_ptr = &py.flags; take_hit(damage, ddesc); if (player_saves()) msg_print("You resist the effects!"); else if (f_ptr->afraid < 1) { msg_print("You are suddenly afraid!"); f_ptr->afraid += 3 + randint((int)r_ptr->level); } else { f_ptr->afraid += 3; notice = FALSE; } break; case 5: /*Fire attack */ msg_print("You are enveloped in flames!"); fire_dam(damage, ddesc); break; case 6: /*Acid attack */ msg_print("You are covered in acid!"); acid_dam(damage, ddesc); break; case 7: /*Cold attack */ msg_print("You are covered with frost!"); cold_dam(damage, ddesc); break; case 8: /*Lightning attack*/ msg_print("Lightning strikes you!"); light_dam(damage, ddesc); break; case 9: /*Corrosion attack*/ msg_print("A stinging red gas swirls about you."); corrode_gas(ddesc); take_hit(damage, ddesc); break; case 10: /*Blindness attack*/ f_ptr = &py.flags; take_hit(damage, ddesc); if (f_ptr->blind < 1) { f_ptr->blind += 10 + randint((int)r_ptr->level); msg_print("Your eyes begin to sting."); } else { f_ptr->blind += 5; notice = FALSE; } break; case 11: /*Paralysis attack*/ f_ptr = &py.flags; take_hit(damage, ddesc); if (player_saves()) msg_print("You resist the effects!"); else if (f_ptr->paralysis < 1) { if (f_ptr->free_act) msg_print("You are unaffected."); else { f_ptr->paralysis = randint((int)r_ptr->level) + 3; msg_print("You are paralyzed."); } } else notice = FALSE; break; case 12: /*Steal Money */ if ((py.flags.paralysis < 1) && (randint(124) < py.stats.use_stat[A_DEX])) msg_print("You quickly protect your money pouch!"); else { gold = (p_ptr->au/10) + randint(25); if (gold > p_ptr->au) p_ptr->au = 0; else p_ptr->au -= gold; msg_print("Your purse feels lighter."); prt_gold(); } if (randint(2) == 1) { msg_print("There is a puff of smoke!"); teleport_away(monptr, MAX_SIGHT); } break; case 13: /*Steal Object */ if ((py.flags.paralysis < 1) && (randint(124) < py.stats.use_stat[A_DEX])) msg_print("You grab hold of your backpack!"); else { i = randint(inven_ctr) - 1; inven_destroy(i); msg_print("Your backpack feels lighter."); } if (randint(2) == 1) { msg_print("There is a puff of smoke!"); teleport_away(monptr, MAX_SIGHT); } break; case 14: /*Poison */ f_ptr = &py.flags; take_hit(damage, ddesc); msg_print("You feel very sick."); f_ptr->poisoned += randint((int)r_ptr->level)+5; break; case 15: /*Lose dexterity */ f_ptr = &py.flags; take_hit(damage, ddesc); if (f_ptr->sustain_dex) msg_print("You feel clumsy for a moment, but it passes."); else { msg_print("You feel more clumsy."); (void) dec_stat (A_DEX); } break; case 16: /*Lose constitution */ f_ptr = &py.flags; take_hit(damage, ddesc); if (f_ptr->sustain_con) msg_print("Your body resists the effects of the disease."); else { msg_print("Your health is damaged!"); (void) dec_stat (A_CON); } break; case 17: /*Lose intelligence */ f_ptr = &py.flags; take_hit(damage, ddesc); msg_print("You have trouble thinking clearly."); if (f_ptr->sustain_int) msg_print("But your mind quickly clears."); else (void) dec_stat (A_INT); break; case 18: /*Lose wisdom */ f_ptr = &py.flags; take_hit(damage, ddesc); if (f_ptr->sustain_wis) msg_print("Your wisdom is sustained."); else { msg_print("Your wisdom is drained."); (void) dec_stat (A_WIS); } break; case 19: /*Lose experience */ msg_print("You feel your life draining away!"); lose_exp(damage + (py.misc.exp / 100)*MON_DRAIN_LIFE); break; case 20: /*Aggravate monster*/ (void) aggravate_monster(20); break; case 21: /*Disenchant */ flag = FALSE; switch(randint(7)) { case 1: i = INVEN_WIELD; break; case 2: i = INVEN_BODY; break; case 3: i = INVEN_ARM; break; case 4: i = INVEN_OUTER; break; case 5: i = INVEN_HANDS; break; case 6: i = INVEN_HEAD; break; case 7: i = INVEN_FEET; break; } i_ptr = &inventory[i]; if (i_ptr->tohit > 0) { i_ptr->tohit -= randint(2); /* don't send it below zero */ if (i_ptr->tohit < 0) i_ptr->tohit = 0; flag = TRUE; } if (i_ptr->todam > 0) { i_ptr->todam -= randint(2); /* don't send it below zero */ if (i_ptr->todam < 0) i_ptr->todam = 0; flag = TRUE; } if (i_ptr->toac > 0) { i_ptr->toac -= randint(2); /* don't send it below zero */ if (i_ptr->toac < 0) i_ptr->toac = 0; flag = TRUE; } if (flag) { msg_print("There is a static feeling in the air."); calc_bonuses (); } else notice = FALSE; break; case 22: /*Eat food */ if (find_range(TV_FOOD, TV_NEVER, &i, &j)) { inven_destroy(i); msg_print ("It got at your rations!"); } else notice = FALSE; break; case 23: /*Eat light */ i_ptr = &inventory[INVEN_LIGHT]; if (i_ptr->p1 > 0) { i_ptr->p1 -= (250 + randint(250)); if (i_ptr->p1 < 1) i_ptr->p1 = 1; if (py.flags.blind < 1) msg_print("Your light dims."); else notice = FALSE; } else notice = FALSE; break; case 24: /*Eat charges */ i = randint(inven_ctr) - 1; j = r_ptr->level; i_ptr = &inventory[i]; if (((i_ptr->tval == TV_STAFF) || (i_ptr->tval == TV_WAND)) && (i_ptr->p1 > 0)) { m_ptr->hp += j*i_ptr->p1; i_ptr->p1 = 0; if (! known2_p (i_ptr)) add_inscribe (i_ptr, ID_EMPTY); msg_print("Energy drains from your pack!"); } else notice = FALSE; break; case 99: notice = FALSE; break; default: notice = FALSE; break; } /* Moved here from mon_move, so that monster only confused if it actually hits. A monster that has been repelled has not hit the player, so it should not be confused. */ if (py.flags.confuse_monster && adesc != 99) { msg_print("Your hands stop glowing."); py.flags.confuse_monster = FALSE; if ((randint(MAX_MONS_LEVEL) < r_ptr->level) || (CD_NO_SLEEP & r_ptr->cdefense)) (void) sprintf(tmp_str, "%sis unaffected.", cdesc); else { (void) sprintf(tmp_str, "%sappears confused.", cdesc); if (m_ptr->confused) m_ptr->confused += 3; else m_ptr->confused = 2 + randint(16); } msg_print(tmp_str); if (visible && !death && randint(4) == 1) c_recall[m_ptr->mptr].r_cdefense |= r_ptr->cdefense & CD_NO_SLEEP; } /* increase number of attacks if notice true, or if visible and had previously noticed the attack (in which case all this does is help player learn damage), note that in the second case do not increase attacks if creature repelled (no damage done) */ if ((notice || (visible && c_recall[m_ptr->mptr].r_attacks[attackn] != 0 && attype != 99)) && c_recall[m_ptr->mptr].r_attacks[attackn] < MAX_UCHAR) c_recall[m_ptr->mptr].r_attacks[attackn]++; if (death && c_recall[m_ptr->mptr].r_deaths < MAX_SHORT) c_recall[m_ptr->mptr].r_deaths++; } else { if ((adesc >= 1 && adesc <= 3) || (adesc == 6)) { disturb (1, 0); (void) strcpy(tmp_str, cdesc); msg_print(strcat(tmp_str, "misses you.")); } } if (attackn < MAX_MON_NATTACK-1) attackn++; else break; } } /* Make the move if possible, five choices -RAK- */ static void make_move(monptr, mm, rcmove) int monptr; int *mm; int32u *rcmove; { int i, newy, newx, do_turn, do_move, stuck_door; int32u movebits; register cave_type *c_ptr; register monster_type *m_ptr; register inven_type *t_ptr; #ifdef ATARIST_MWC int32u holder; #endif i = 0; do_turn = FALSE; do_move = FALSE; m_ptr = &m_list[monptr]; movebits = c_list[m_ptr->mptr].cmove; do { /* Get new position */ newy = m_ptr->fy; newx = m_ptr->fx; (void) mmove(mm[i], &newy, &newx); c_ptr = &cave[newy][newx]; if (c_ptr->fval != BOUNDARY_WALL) { /* Floor is open? */ if (c_ptr->fval <= MAX_OPEN_SPACE) do_move = TRUE; /* Creature moves through walls? */ #ifdef ATARIST_MWC else if (movebits & (holder = CM_PHASE)) #else else if (movebits & CM_PHASE) #endif { do_move = TRUE; #ifdef ATARIST_MWC *rcmove |= holder; #else *rcmove |= CM_PHASE; #endif } /* Creature can open doors? */ else if (c_ptr->tptr != 0) { t_ptr = &t_list[c_ptr->tptr]; #ifdef ATARIST_MWC if (movebits & (holder = CM_OPEN_DOOR)) #else if (movebits & CM_OPEN_DOOR) #endif { /* Creature can open doors. */ stuck_door = FALSE; if (t_ptr->tval == TV_CLOSED_DOOR) { do_turn = TRUE; if (t_ptr->p1 == 0) /* Closed doors */ do_move = TRUE; else if (t_ptr->p1 > 0) /* Locked doors */ { if (randint((m_ptr->hp+1)*(50+t_ptr->p1)) < 40*(m_ptr->hp-10-t_ptr->p1)) t_ptr->p1 = 0; } else if (t_ptr->p1 < 0) /* Stuck doors */ { if (randint((m_ptr->hp+1)*(50-t_ptr->p1)) < 40*(m_ptr->hp-10+t_ptr->p1)) { msg_print("You hear a door burst open!"); disturb (1, 0); stuck_door = TRUE; do_move = TRUE; } } } else if (t_ptr->tval == TV_SECRET_DOOR) { do_turn = TRUE; do_move = TRUE; } if (do_move) { invcopy(t_ptr, OBJ_OPEN_DOOR); if (stuck_door) /* 50% chance of breaking door */ t_ptr->p1 = 1 - randint(2); c_ptr->fval = CORR_FLOOR; lite_spot(newy, newx); #ifdef ATARIST_MWC *rcmove |= holder; #else *rcmove |= CM_OPEN_DOOR; #endif do_move = FALSE; } } else { /* Creature can not open doors, must bash them */ if (t_ptr->tval == TV_CLOSED_DOOR) { do_turn = TRUE; if (randint((m_ptr->hp+1)*(80+abs(t_ptr->p1))) < 40*(m_ptr->hp-20-abs(t_ptr->p1))) { invcopy(t_ptr, OBJ_OPEN_DOOR); /* 50% chance of breaking door */ t_ptr->p1 = 1 - randint(2); c_ptr->fval = CORR_FLOOR; lite_spot(newy, newx); msg_print ("You hear a door burst open!"); disturb (1, 0); } } } } /* Glyph of warding present? */ if (do_move && (c_ptr->tptr != 0) && (t_list[c_ptr->tptr].tval == TV_VIS_TRAP) && (t_list[c_ptr->tptr].subval == 99)) { if (randint(OBJ_RUNE_PROT) < c_list[m_ptr->mptr].level) { if ((newy==char_row) && (newx==char_col)) msg_print("The rune of protection is broken!"); (void) delete_object(newy, newx); } else { do_move = FALSE; /* If the creature moves only to attack, */ /* don't let it move if the glyph prevents */ /* it from attacking */ if (movebits & CM_ATTACK_ONLY) do_turn = TRUE; } } /* Creature has attempted to move on player? */ if (do_move) if (c_ptr->cptr == 1) { /* if the monster is not lit, must call update_mon, it may be faster than character, and hence could have just moved next to character this same turn */ if (!m_ptr->ml) update_mon(monptr); make_attack(monptr); do_move = FALSE; do_turn = TRUE; } /* Creature is attempting to move on other creature? */ else if ((c_ptr->cptr > 1) && ((newy != m_ptr->fy) || (newx != m_ptr->fx))) { /* Creature eats other creatures? */ #ifdef ATARIST_MWC if ((movebits & (holder = CM_EATS_OTHER)) && #else if ((movebits & CM_EATS_OTHER) && #endif (c_list[m_ptr->mptr].mexp >= c_list[m_list[c_ptr->cptr].mptr].mexp)) { if (m_list[c_ptr->cptr].ml) #ifdef ATARIST_MWC *rcmove |= holder; #else *rcmove |= CM_EATS_OTHER; #endif /* It ate an already processed monster. Handle normally. */ if (monptr < c_ptr->cptr) delete_monster((int) c_ptr->cptr); /* If it eats this monster, an already processed monster will take its place, causing all kinds of havoc. Delay the kill a bit. */ else fix1_delete_monster((int) c_ptr->cptr); } else do_move = FALSE; } /* Creature has been allowed move. */ if (do_move) { /* Pick up or eat an object */ #ifdef ATARIST_MWC if (movebits & (holder = CM_PICKS_UP)) #else if (movebits & CM_PICKS_UP) #endif { c_ptr = &cave[newy][newx]; if ((c_ptr->tptr != 0) && (t_list[c_ptr->tptr].tval <= TV_MAX_OBJECT)) { #ifdef ATARIST_MWC *rcmove |= holder; #else *rcmove |= CM_PICKS_UP; #endif (void) delete_object(newy, newx); } } /* Move creature record */ move_rec((int)m_ptr->fy, (int)m_ptr->fx, newy, newx); if (m_ptr->ml) { m_ptr->ml = FALSE; lite_spot ((int)m_ptr->fy, (int)m_ptr->fx); } m_ptr->fy = newy; m_ptr->fx = newx; m_ptr->cdis = distance (char_row, char_col, newy, newx); do_turn = TRUE; } } i++; /* Up to 5 attempts at moving, give up. */ } while ((!do_turn) && (i < 5)); } /* Creatures can cast spells too. (Dragon Breath) -RAK- */ /* cast_spell = true if creature changes position */ /* took_turn = true if creature casts a spell */ static void mon_cast_spell(monptr, took_turn) int monptr; int *took_turn; { int32u i; int y, x, chance, thrown_spell, r1; register int k; int spell_choice[30]; vtype cdesc, outval, ddesc; register monster_type *m_ptr; register creature_type *r_ptr; #ifdef ATARIST_MWC int32u holder; #endif if (death) return; m_ptr = &m_list[monptr]; r_ptr = &c_list[m_ptr->mptr]; chance = (int)(r_ptr->spells & CS_FREQ); /* 1 in x chance of casting spell */ if (randint(chance) != 1) *took_turn = FALSE; /* Must be within certain range */ else if (m_ptr->cdis > MAX_SPELL_DIS) *took_turn = FALSE; /* Must have unobstructed Line-Of-Sight */ else if (!los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx)) *took_turn = FALSE; else /* Creature is going to cast a spell */ { *took_turn = TRUE; /* Check to see if monster should be lit. */ update_mon (monptr); /* Describe the attack */ if (m_ptr->ml) (void) sprintf(cdesc, "The %s ", r_ptr->name); else (void) strcpy(cdesc, "It "); /* For "DIED_FROM" string */ #ifdef ATARIST_MWC holder = CM_WIN; if (holder & r_ptr->cmove) #else if (CM_WIN & r_ptr->cmove) #endif (void) sprintf(ddesc, "The %s", r_ptr->name); else if (is_a_vowel (r_ptr->name[0])) (void) sprintf (ddesc, "an %s", r_ptr->name); else (void) sprintf(ddesc, "a %s", r_ptr->name); /* End DIED_FROM */ /* Extract all possible spells into spell_choice */ #ifdef ATARIST_MWC holder = ~CS_FREQ; i = (r_ptr->spells & holder); #else i = (r_ptr->spells & ~CS_FREQ); #endif k = 0; while (i != 0) { spell_choice[k] = bit_pos(&i); k++; } /* Choose a spell to cast */ thrown_spell = spell_choice[randint(k) - 1]; thrown_spell++; /* all except teleport_away() and drain mana spells always disturb */ if (thrown_spell > 6 && thrown_spell != 17) disturb (1, 0); /* save some code/data space here, with a small time penalty */ if ((thrown_spell < 14 && thrown_spell > 6) || (thrown_spell == 16)) { (void) strcat(cdesc, "casts a spell."); msg_print(cdesc); } /* Cast the spell. */ switch(thrown_spell) { case 5: /*Teleport Short*/ teleport_away(monptr, 5); break; case 6: /*Teleport Long */ teleport_away(monptr, MAX_SIGHT); break; case 7: /*Teleport To */ teleport_to((int)m_ptr->fy, (int)m_ptr->fx); break; case 8: /*Light Wound */ if (player_saves()) msg_print("You resist the effects of the spell."); else take_hit(damroll(3, 8), ddesc); break; case 9: /*Serious Wound */ if (player_saves()) msg_print("You resist the effects of the spell."); else take_hit(damroll(8, 8), ddesc); break; case 10: /*Hold Person */ if (py.flags.free_act) msg_print("You are unaffected."); else if (player_saves()) msg_print("You resist the effects of the spell."); else if (py.flags.paralysis > 0) py.flags.paralysis += 2; else py.flags.paralysis = randint(5)+4; break; case 11: /*Cause Blindness*/ if (player_saves()) msg_print("You resist the effects of the spell."); else if (py.flags.blind > 0) py.flags.blind += 6; else py.flags.blind += 12 + randint(3); break; case 12: /*Cause Confuse */ if (player_saves()) msg_print("You resist the effects of the spell."); else if (py.flags.confused > 0) py.flags.confused += 2; else py.flags.confused = randint(5) + 3; break; case 13: /*Cause Fear */ if (player_saves()) msg_print("You resist the effects of the spell."); else if (py.flags.afraid > 0) py.flags.afraid += 2; else py.flags.afraid = randint(5) + 3; break; case 14: /*Summon Monster*/ (void) strcat(cdesc, "magically summons a monster!"); msg_print(cdesc); y = char_row; x = char_col; /* in case compact_monster() is called,it needs monptr */ hack_monptr = monptr; (void) summon_monster(&y, &x, FALSE); hack_monptr = -1; update_mon ((int)cave[y][x].cptr); break; case 15: /*Summon Undead*/ (void) strcat(cdesc, "magically summons an undead!"); msg_print(cdesc); y = char_row; x = char_col; /* in case compact_monster() is called,it needs monptr */ hack_monptr = monptr; (void) summon_undead(&y, &x); hack_monptr = -1; update_mon ((int)cave[y][x].cptr); break; case 16: /*Slow Person */ if (py.flags.free_act) msg_print("You are unaffected."); else if (player_saves()) msg_print("You resist the effects of the spell."); else if (py.flags.slow > 0) py.flags.slow += 2; else py.flags.slow = randint(5) + 3; break; case 17: /*Drain Mana */ if (py.misc.cmana > 0) { disturb (1, 0); (void) sprintf(outval, "%sdraws psychic energy from you!",cdesc); msg_print(outval); if (m_ptr->ml) { (void) sprintf(outval, "%sappears healthier.", cdesc); msg_print(outval); } r1 = (randint((int)r_ptr->level) >> 1) + 1; if (r1 > py.misc.cmana) { r1 = py.misc.cmana; py.misc.cmana = 0; py.misc.cmana_frac = 0; } else py.misc.cmana -= r1; prt_cmana(); m_ptr->hp += 6*(r1); } break; case 20: /*Breath Light */ (void) strcat(cdesc, "breathes lightning."); msg_print(cdesc); breath(GF_LIGHTNING, char_row, char_col, (m_ptr->hp / 4), ddesc, monptr); break; case 21: /*Breath Gas */ (void) strcat(cdesc, "breathes gas."); msg_print(cdesc); breath(GF_POISON_GAS, char_row, char_col, (m_ptr->hp / 3), ddesc, monptr); break; case 22: /*Breath Acid */ (void) strcat(cdesc, "breathes acid."); msg_print(cdesc); breath(GF_ACID, char_row, char_col, (m_ptr->hp / 3), ddesc, monptr); break; case 23: /*Breath Frost */ (void) strcat(cdesc, "breathes frost."); msg_print(cdesc); breath(GF_FROST, char_row, char_col, (m_ptr->hp / 3), ddesc, monptr); break; case 24: /*Breath Fire */ (void) strcat(cdesc, "breathes fire."); msg_print(cdesc); breath(GF_FIRE, char_row, char_col, (m_ptr->hp / 3), ddesc, monptr); break; default: (void) strcat (cdesc, "cast unknown spell."); msg_print(cdesc); } /* End of spells */ if (m_ptr->ml) { c_recall[m_ptr->mptr].r_spells |= 1L << (thrown_spell-1); if ((c_recall[m_ptr->mptr].r_spells & CS_FREQ) != CS_FREQ) c_recall[m_ptr->mptr].r_spells++; if (death && c_recall[m_ptr->mptr].r_deaths < MAX_SHORT) c_recall[m_ptr->mptr].r_deaths++; } } } /* Places creature adjacent to given location -RAK- */ /* Rats and Flys are fun! */ int multiply_monster(y, x, cr_index, monptr) int y, x, cr_index; int monptr; { register int i, j, k; register cave_type *c_ptr; int result; #ifdef ATARIST_MWC int32u holder; #endif i = 0; do { j = y - 2 + randint(3); k = x - 2 + randint(3); /* don't create a new creature on top of the old one, that causes invincible/invisible creatures to appear */ if (in_bounds(j, k) && (j != y || k != x)) { c_ptr = &cave[j][k]; if ((c_ptr->fval <= MAX_OPEN_SPACE) && (c_ptr->tptr == 0) && (c_ptr->cptr != 1)) { if (c_ptr->cptr > 1) /* Creature there already? */ { /* Some critters are cannibalistic! */ #ifdef ATARIST_MWC holder = CM_EATS_OTHER; if ((c_list[cr_index].cmove & holder) #else if ((c_list[cr_index].cmove & CM_EATS_OTHER) #endif /* Check the experience level -CJS- */ && c_list[cr_index].mexp >= c_list[m_list[c_ptr->cptr].mptr].mexp) { /* It ate an already processed monster.Handle normally.*/ if (monptr < c_ptr->cptr) delete_monster((int) c_ptr->cptr); /* If it eats this monster, an already processed mosnter will take its place, causing all kinds of havoc. Delay the kill a bit. */ else fix1_delete_monster((int) c_ptr->cptr); /* in case compact_monster() is called,it needs monptr */ hack_monptr = monptr; /* Place_monster() may fail if monster list full. */ result = place_monster(j, k, cr_index, FALSE); hack_monptr = -1; if (! result) return FALSE; mon_tot_mult++; return check_mon_lite(j, k); } } else /* All clear, place a monster */ { /* in case compact_monster() is called,it needs monptr */ hack_monptr = monptr; /* Place_monster() may fail if monster list full. */ result = place_monster(j, k, cr_index, FALSE); hack_monptr = -1; if (! result) return FALSE; mon_tot_mult++; return check_mon_lite(j, k); } } } i++; } while (i <= 18); return FALSE; } /* Move the critters about the dungeon -RAK- */ static void mon_move(monptr, rcmove) int monptr; int32u *rcmove; { register int i, j; int k, move_test, dir; #ifdef M_XENIX /* Avoid 'register' bug. */ creature_type *r_ptr; #else register creature_type *r_ptr; #endif register monster_type *m_ptr; int mm[9]; #ifdef ATARIST_MWC int32u holder; #endif int rest_val; m_ptr = &m_list[monptr]; r_ptr = &c_list[m_ptr->mptr]; /* Does the critter multiply? */ /* rest could be negative, to be safe, only use mod with positive values. */ rest_val = abs (py.flags.rest); #ifdef ATARIST_MWC holder = CM_MULTIPLY; if ((r_ptr->cmove & holder) && (MAX_MON_MULT >= mon_tot_mult) && #else if ((r_ptr->cmove & CM_MULTIPLY) && (MAX_MON_MULT >= mon_tot_mult) && #endif ((rest_val % MON_MULT_ADJ) == 0)) { k = 0; for (i = m_ptr->fy-1; i <= m_ptr->fy+1; i++) for (j = m_ptr->fx-1; j <= m_ptr->fx+1; j++) if (in_bounds(i, j) && (cave[i][j].cptr > 1)) k++; /* can't call randint with a value of zero, increment counter to allow creature multiplication */ if (k == 0) k++; if ((k < 4) && (randint(k*MON_MULT_ADJ) == 1)) if (multiply_monster((int)m_ptr->fy, (int)m_ptr->fx, (int)m_ptr->mptr, monptr)) #ifdef ATARIST_MWC *rcmove |= holder; #else *rcmove |= CM_MULTIPLY; #endif } move_test = FALSE; /* if in wall, must immediately escape to a clear area */ #ifdef ATARIST_MWC holder = CM_PHASE; if (!(r_ptr->cmove & holder) && #else if (!(r_ptr->cmove & CM_PHASE) && #endif (cave[m_ptr->fy][m_ptr->fx].fval >= MIN_CAVE_WALL)) { /* If the monster is already dead, don't kill it again! This can happen for monsters moving faster than the player. They will get multiple moves, but should not if they die on the first move. This is only a problem for monsters stuck in rock. */ if (m_ptr->hp < 0) return; k = 0; dir = 1; /* note direction of for loops matches direction of keypad from 1 to 9*/ /* do not allow attack against the player */ /* Must cast fy-1 to signed int, so that a nagative value of i will fail the comparison. */ for (i = m_ptr->fy+1; i >= (int)(m_ptr->fy-1); i--) for (j = m_ptr->fx-1; j <= m_ptr->fx+1; j++) { if ((dir != 5) && (cave[i][j].fval <= MAX_OPEN_SPACE) && (cave[i][j].cptr != 1)) mm[k++] = dir; dir++; } if (k != 0) { /* put a random direction first */ dir = randint (k) - 1; i = mm[0]; mm[0] = mm[dir]; mm[dir] = i; make_move (monptr, mm, rcmove); /* this can only fail if mm[0] has a rune of protection */ } /* if still in a wall, let it dig itself out, but also apply some more damage */ if (cave[m_ptr->fy][m_ptr->fx].fval >= MIN_CAVE_WALL) { /* in case the monster dies, may need to call fix1_delete_monster() instead of delete_monsters() */ hack_monptr = monptr; i = mon_take_hit(monptr, damroll (8, 8)); hack_monptr = -1; if (i >= 0) { msg_print("You hear a scream muffled by rock!"); prt_experience(); } else { msg_print ("A creature digs itself out from the rock!"); (void) twall ((int)m_ptr->fy, (int)m_ptr->fx, 1, 0); } } return; /* monster movement finished */ } /* Creature is confused or undead turned? */ else if (m_ptr->confused) { if (r_ptr->cdefense & CD_UNDEAD) /* Undead only get confused from turn undead, so they should flee */ { get_moves(monptr,mm); mm[0] = 10-mm[0]; mm[1] = 10-mm[1]; mm[2] = 10-mm[2]; mm[3] = randint(9); /* May attack only if cornered */ mm[4] = randint(9); } else { mm[0] = randint(9); mm[1] = randint(9); mm[2] = randint(9); mm[3] = randint(9); mm[4] = randint(9); } /* don't move him if he is not supposed to move! */ if (!(r_ptr->cmove & CM_ATTACK_ONLY)) make_move(monptr, mm, rcmove); m_ptr->confused--; move_test = TRUE; } /* Creature may cast a spell */ #ifdef ATARIST_MWC else if (r_ptr->spells & (holder = CS_FREQ)) #else else if (r_ptr->spells & CS_FREQ) #endif mon_cast_spell(monptr, &move_test); if (!move_test) { /* 75% random movement */ if ((r_ptr->cmove & CM_75_RANDOM) && (randint(100) < 75)) { mm[0] = randint(9); mm[1] = randint(9); mm[2] = randint(9); mm[3] = randint(9); mm[4] = randint(9); *rcmove |= CM_75_RANDOM; make_move(monptr, mm, rcmove); } /* 40% random movement */ else if ((r_ptr->cmove & CM_40_RANDOM) && (randint(100) < 40)) { mm[0] = randint(9); mm[1] = randint(9); mm[2] = randint(9); mm[3] = randint(9); mm[4] = randint(9); *rcmove |= CM_40_RANDOM; make_move(monptr, mm, rcmove); } /* 20% random movement */ else if ((r_ptr->cmove & CM_20_RANDOM) && (randint(100) < 20)) { mm[0] = randint(9); mm[1] = randint(9); mm[2] = randint(9); mm[3] = randint(9); mm[4] = randint(9); *rcmove |= CM_20_RANDOM; make_move(monptr, mm, rcmove); } /* Normal movement */ else if (r_ptr->cmove & CM_MOVE_NORMAL) { if (randint(200) == 1) { mm[0] = randint(9); mm[1] = randint(9); mm[2] = randint(9); mm[3] = randint(9); mm[4] = randint(9); } else get_moves(monptr, mm); *rcmove |= CM_MOVE_NORMAL; make_move(monptr, mm, rcmove); } /* Attack, but don't move */ else if (r_ptr->cmove & CM_ATTACK_ONLY) { if (m_ptr->cdis < 2) { get_moves(monptr, mm); make_move(monptr, mm, rcmove); } else /* Learn that the monster does does not move when it should have moved, but didn't. */ *rcmove |= CM_ATTACK_ONLY; } else if ((r_ptr->cmove & CM_ONLY_MAGIC) && (m_ptr->cdis < 2)) { /* A little hack for Quylthulgs, so that one will eventually notice that they have no physical attacks. */ if (c_recall[m_ptr->mptr].r_attacks[0] < MAX_UCHAR) c_recall[m_ptr->mptr].r_attacks[0]++; /* Another little hack for Quylthulgs, so that one can eventually learn their speed. */ if (c_recall[m_ptr->mptr].r_attacks[0] > 20) c_recall[m_ptr->mptr].r_cmove |= CM_ONLY_MAGIC; } } } /* Creatures movement and attacking are done from here -RAK- */ void creatures(attack) int attack; { register int i, k; register monster_type *m_ptr; recall_type *r_ptr; int32u notice, rcmove; int wake, ignore; vtype cdesc; #ifdef ATARIST_MWC int32u holder; #endif /* Process the monsters */ for (i = mfptr - 1; i >= MIN_MONIX && !death; i--) { m_ptr = &m_list[i]; /* Get rid of an eaten/breathed on monster. Note: Be sure not to process this monster. This is necessary because we can't delete monsters while scanning the m_list here. */ if (m_ptr->hp < 0) { fix2_delete_monster(i); continue; } m_ptr->cdis = distance(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx); if (attack) /* Attack is argument passed to CREATURE*/ { k = movement_rate(m_ptr->cspeed); if (k <= 0) update_mon(i); else while (k > 0) { k--; wake = FALSE; ignore = FALSE; rcmove = 0; if (m_ptr->ml || (m_ptr->cdis <= c_list[m_ptr->mptr].aaf) /* Monsters trapped in rock must be given a turn also, so that they will die/dig out immediately. */ #ifdef ATARIST_MWC || ((! (c_list[m_ptr->mptr].cmove & (holder = CM_PHASE))) #else || ((! (c_list[m_ptr->mptr].cmove & CM_PHASE)) #endif && cave[m_ptr->fy][m_ptr->fx].fval >= MIN_CAVE_WALL)) { if (m_ptr->csleep > 0) if (py.flags.aggravate) m_ptr->csleep = 0; else if ((py.flags.rest == 0 && py.flags.paralysis < 1) || (randint(50) == 1)) { notice = randint(1024); if (notice*notice*notice <= (1L << (29 - py.misc.stl))) { m_ptr->csleep -= (100 / m_ptr->cdis); if (m_ptr->csleep > 0) ignore = TRUE; else { wake = TRUE; /* force it to be exactly zero */ m_ptr->csleep = 0; } } } if (m_ptr->stunned != 0) { /* NOTE: Balrog = 100*100 = 10000, it always recovers instantly */ if (randint(5000) < c_list[m_ptr->mptr].level * c_list[m_ptr->mptr].level) m_ptr->stunned = 0; else m_ptr->stunned--; if (m_ptr->stunned == 0) { if (m_ptr->ml) { (void) sprintf(cdesc, "The %s ", c_list[m_ptr->mptr].name); msg_print(strcat(cdesc, "recovers and glares at you.")); } } } if ((m_ptr->csleep == 0) && (m_ptr->stunned == 0)) mon_move (i, &rcmove); } update_mon(i); if (m_ptr->ml) { r_ptr = &c_recall[m_ptr->mptr]; if (wake) { if (r_ptr->r_wake < MAX_UCHAR) r_ptr->r_wake++; } else if (ignore) { if (r_ptr->r_ignore < MAX_UCHAR) r_ptr->r_ignore++; } r_ptr->r_cmove |= rcmove; } } } else update_mon(i); /* Get rid of an eaten/breathed on monster. This is necessary because we can't delete monsters while scanning the m_list here. This monster may have been killed during mon_move(). */ if (m_ptr->hp < 0) { fix2_delete_monster(i); continue; } } /* End processing monsters */ } moria-5.6.debian.1/source/dungeon.c0000644000175000017500000014251011074756544015306 0ustar pjbpjb/* source/dungeon.c: the main command interpreter, updating player status Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #ifdef __TURBOC__ #include #endif /* __TURBOC__ */ #include #include #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #ifdef USG #ifndef ATARIST_MWC #include #endif #else #include #endif #if defined(LINT_ARGS) static char original_commands(char); static void do_command(char); static int valid_countcommand(char); static void regenhp(int); static void regenmana(int); static int enchanted(inven_type *); static void examine_book(void); static void go_up(void); static void go_down(void); static void jamdoor(void); static void refill_lamp(void); #else static char original_commands(); static void do_command(); static int valid_countcommand(); static void regenhp(); static void regenmana(); static int enchanted(); static void examine_book(); static void go_up(); static void go_down(); static void jamdoor(); static void refill_lamp(); #endif #ifdef ATARIST_TC /* Include this to get prototypes for standard library functions. */ #include #endif /* Moria game module -RAK- */ /* The code in this section has gone through many revisions, and */ /* some of it could stand some more hard work. -RAK- */ /* It has had a bit more hard work. -CJS- */ void dungeon() { int find_count, i; int regen_amount; /* Regenerate hp and mana*/ char command; /* Last command */ register struct misc *p_ptr; register inven_type *i_ptr; register struct flags *f_ptr; #ifdef ATARIST_WMC int32u holder; #endif /* Main procedure for dungeon. -RAK- */ /* Note: There is a lot of preliminary magic going on here at first*/ /* init pointers. */ f_ptr = &py.flags; p_ptr = &py.misc; /* Check light status for setup */ i_ptr = &inventory[INVEN_LIGHT]; if (i_ptr->p1 > 0) player_light = TRUE; else player_light = FALSE; /* Check for a maximum level */ if (dun_level > p_ptr->max_dlv) p_ptr->max_dlv = dun_level; /* Reset flags and initialize variables */ command_count = 0; find_count = 0; new_level_flag = FALSE; find_flag = FALSE; teleport_flag = FALSE; mon_tot_mult = 0; cave[char_row][char_col].cptr = 1; /* Ensure we display the panel. Used to do this with a global var. -CJS- */ panel_row = panel_col = -1; /* Light up the area around character */ check_view (); /* must do this after panel_row/col set to -1, because search_off() will call check_view(), and so the panel_* variables must be valid before search_off() is called */ if (py.flags.status & PY_SEARCH) search_off(); /* Light, but do not move critters */ creatures(FALSE); /* Print the depth */ prt_depth(); #if 0 /* This can't be right. */ #ifdef ATARIST_MWC prt_map(); #endif #endif /* Loop until dead, or new level */ do { /* Increment turn counter */ turn++; #ifndef MAC /* The Mac ignores the game hours file */ /* Check for game hours */ if (((turn % 250) == 1) && !check_time()) if (closing_flag > 4) { msg_print("The gates to Moria are now closed."); (void) strcpy (died_from, "(closing gate: saved)"); if (!save_char()) { (void) strcpy (died_from, "a slammed gate"); death = TRUE; } exit_game(); } else { disturb (0, 0); closing_flag++; msg_print("The gates to Moria are closing."); msg_print("Please finish up or save your game."); } #endif /* turn over the store contents every, say, 1000 turns */ if ((dun_level != 0) && ((turn % 1000) == 0)) store_maint(); /* Check for creature generation */ if (randint(MAX_MALLOC_CHANCE) == 1) alloc_monster(1, MAX_SIGHT, FALSE); /* Check light status */ i_ptr = &inventory[INVEN_LIGHT]; if (player_light) if (i_ptr->p1 > 0) { i_ptr->p1--; if (i_ptr->p1 == 0) { player_light = FALSE; msg_print("Your light has gone out!"); disturb (0, 1); /* unlight creatures */ creatures(FALSE); } else if ((i_ptr->p1 < 40) && (randint(5) == 1) && (py.flags.blind < 1)) { disturb (0, 0); msg_print("Your light is growing faint."); } } else { player_light = FALSE; disturb (0, 1); /* unlight creatures */ creatures(FALSE); } else if (i_ptr->p1 > 0) { i_ptr->p1--; player_light = TRUE; disturb (0, 1); /* light creatures */ creatures(FALSE); } /* Update counters and messages */ /* Heroism (must precede anything that can damage player) */ if (f_ptr->hero > 0) { if ((PY_HERO & f_ptr->status) == 0) { f_ptr->status |= PY_HERO; disturb (0, 0); p_ptr->mhp += 10; p_ptr->chp += 10; p_ptr->bth += 12; p_ptr->bthb+= 12; msg_print("You feel like a HERO!"); prt_mhp(); prt_chp(); } f_ptr->hero--; if (f_ptr->hero == 0) { #ifdef ATARIST_MWC f_ptr->status &= ~(holder = PY_HERO); #else f_ptr->status &= ~PY_HERO; #endif disturb (0, 0); p_ptr->mhp -= 10; if (p_ptr->chp > p_ptr->mhp) { p_ptr->chp = p_ptr->mhp; p_ptr->chp_frac = 0; prt_chp(); } p_ptr->bth -= 12; p_ptr->bthb-= 12; msg_print("The heroism wears off."); prt_mhp(); } } /* Super Heroism */ if (f_ptr->shero > 0) { if ((PY_SHERO & f_ptr->status) == 0) { f_ptr->status |= PY_SHERO; disturb (0, 0); p_ptr->mhp += 20; p_ptr->chp += 20; p_ptr->bth += 24; p_ptr->bthb+= 24; msg_print("You feel like a SUPER HERO!"); prt_mhp(); prt_chp(); } f_ptr->shero--; if (f_ptr->shero == 0) { #ifdef ATARIST_MWC f_ptr->status &= ~(holder = PY_SHERO); #else f_ptr->status &= ~PY_SHERO; #endif disturb (0, 0); p_ptr->mhp -= 20; if (p_ptr->chp > p_ptr->mhp) { p_ptr->chp = p_ptr->mhp; p_ptr->chp_frac = 0; prt_chp(); } p_ptr->bth -= 24; p_ptr->bthb-= 24; msg_print("The super heroism wears off."); prt_mhp(); } } /* Check food status */ regen_amount = PLAYER_REGEN_NORMAL; if (f_ptr->food < PLAYER_FOOD_ALERT) { if (f_ptr->food < PLAYER_FOOD_WEAK) { if (f_ptr->food < 0) regen_amount = 0; else if (f_ptr->food < PLAYER_FOOD_FAINT) regen_amount = PLAYER_REGEN_FAINT; else if (f_ptr->food < PLAYER_FOOD_WEAK) regen_amount = PLAYER_REGEN_WEAK; if ((PY_WEAK & f_ptr->status) == 0) { f_ptr->status |= PY_WEAK; msg_print("You are getting weak from hunger."); disturb (0, 0); prt_hunger(); } if ((f_ptr->food < PLAYER_FOOD_FAINT) && (randint(8) == 1)) { f_ptr->paralysis += randint(5); msg_print("You faint from the lack of food."); disturb (1, 0); } } else if ((PY_HUNGRY & f_ptr->status) == 0) { f_ptr->status |= PY_HUNGRY; msg_print("You are getting hungry."); disturb (0, 0); prt_hunger(); } } /* Food consumption */ /* Note: Speeded up characters really burn up the food! */ if (f_ptr->speed < 0) f_ptr->food -= f_ptr->speed*f_ptr->speed; f_ptr->food -= f_ptr->food_digested; if (f_ptr->food < 0) { take_hit (-f_ptr->food/16, "starvation"); /* -CJS- */ disturb(1, 0); } /* Regenerate */ if (f_ptr->regenerate) regen_amount = regen_amount * 3 / 2; if ((py.flags.status & PY_SEARCH) || f_ptr->rest != 0) regen_amount = regen_amount * 2; if ((py.flags.poisoned < 1) && (p_ptr->chp < p_ptr->mhp)) regenhp(regen_amount); if (p_ptr->cmana < p_ptr->mana) regenmana(regen_amount); /* Blindness */ if (f_ptr->blind > 0) { if ((PY_BLIND & f_ptr->status) == 0) { f_ptr->status |= PY_BLIND; prt_map(); prt_blind(); disturb (0, 1); /* unlight creatures */ creatures (FALSE); } f_ptr->blind--; if (f_ptr->blind == 0) { #ifdef ATARIST_MWC f_ptr->status &= ~(holder = PY_BLIND); #else f_ptr->status &= ~PY_BLIND; #endif prt_blind(); prt_map(); /* light creatures */ disturb (0, 1); creatures(FALSE); msg_print("The veil of darkness lifts."); } } /* Confusion */ if (f_ptr->confused > 0) { if ((PY_CONFUSED & f_ptr->status) == 0) { f_ptr->status |= PY_CONFUSED; prt_confused(); } f_ptr->confused--; if (f_ptr->confused == 0) { #ifdef ATARIST_MWC f_ptr->status &= ~(holder = PY_CONFUSED); #else f_ptr->status &= ~PY_CONFUSED; #endif prt_confused(); msg_print("You feel less confused now."); if (py.flags.rest != 0) rest_off (); } } /* Afraid */ if (f_ptr->afraid > 0) { if ((PY_FEAR & f_ptr->status) == 0) { if ((f_ptr->shero+f_ptr->hero) > 0) f_ptr->afraid = 0; else { f_ptr->status |= PY_FEAR; prt_afraid(); } } else if ((f_ptr->shero+f_ptr->hero) > 0) f_ptr->afraid = 1; f_ptr->afraid--; if (f_ptr->afraid == 0) { #ifdef ATARIST_MWC f_ptr->status &= ~(holder = PY_FEAR); #else f_ptr->status &= ~PY_FEAR; #endif prt_afraid(); msg_print("You feel bolder now."); disturb (0, 0); } } /* Poisoned */ if (f_ptr->poisoned > 0) { if ((PY_POISONED & f_ptr->status) == 0) { f_ptr->status |= PY_POISONED; prt_poisoned(); } f_ptr->poisoned--; if (f_ptr->poisoned == 0) { #ifdef ATARIST_MWC f_ptr->status &= ~(holder = PY_POISONED); #else f_ptr->status &= ~PY_POISONED; #endif prt_poisoned(); msg_print("You feel better."); disturb (0, 0); } else { switch(con_adj()) { case -4: i = 4; break; case -3: case -2: i = 3; break; case -1: i = 2; break; case 0: i = 1; break; case 1: case 2: case 3: i = ((turn % 2) == 0); break; case 4: case 5: i = ((turn % 3) == 0); break; case 6: i = ((turn % 4) == 0); break; } take_hit (i, "poison"); disturb (1, 0); } } /* Fast */ if (f_ptr->fast > 0) { if ((PY_FAST & f_ptr->status) == 0) { f_ptr->status |= PY_FAST; change_speed(-1); msg_print("You feel yourself moving faster."); disturb (0, 0); } f_ptr->fast--; if (f_ptr->fast == 0) { #ifdef ATARIST_MWC f_ptr->status &= ~(holder = PY_FAST); #else f_ptr->status &= ~PY_FAST; #endif change_speed(1); msg_print("You feel yourself slow down."); disturb (0, 0); } } /* Slow */ if (f_ptr->slow > 0) { if ((PY_SLOW & f_ptr->status) == 0) { f_ptr->status |= PY_SLOW; change_speed(1); msg_print("You feel yourself moving slower."); disturb (0, 0); } f_ptr->slow--; if (f_ptr->slow == 0) { #ifdef ATARIST_MWC f_ptr->status &= ~(holder = PY_SLOW); #else f_ptr->status &= ~PY_SLOW; #endif change_speed(-1); msg_print("You feel yourself speed up."); disturb (0, 0); } } /* Resting is over? */ if (f_ptr->rest > 0) { f_ptr->rest--; if (f_ptr->rest == 0) /* Resting over */ rest_off(); } else if (f_ptr->rest < 0) { /* Rest until reach max mana and max hit points. */ f_ptr->rest++; if ((p_ptr->chp == p_ptr->mhp && p_ptr->cmana == p_ptr->mana) || f_ptr->rest == 0) rest_off(); } /* Check for interrupts to find or rest. */ #ifdef MAC /* On Mac, checking for input is expensive, since it involves handling events, so we only check in multiples of 16 turns. */ if (!(turn & 0xF) && ((command_count > 0) || find_flag || (f_ptr->rest != 0))) if (macgetkey(CNIL, TRUE)) disturb(0, 0); #else if ((command_count > 0 || find_flag || f_ptr->rest != 0) #if defined(MSDOS) || defined(VMS) && kbhit() #else && (check_input (find_flag ? 0 : 10000)) #endif ) { #ifdef MSDOS (void) msdos_getch(); #endif #ifdef VMS /* Get and ignore the key used to interrupt resting/running. */ (void) vms_getch (); #endif disturb (0, 0); } #endif /* Hallucinating? (Random characters appear!)*/ if (f_ptr->image > 0) { end_find (); f_ptr->image--; if (f_ptr->image == 0) prt_map (); /* Used to draw entire screen! -CJS- */ } /* Paralysis */ if (f_ptr->paralysis > 0) { /* when paralysis true, you can not see any movement that occurs */ f_ptr->paralysis--; disturb (1, 0); } /* Protection from evil counter*/ if (f_ptr->protevil > 0) { f_ptr->protevil--; if (f_ptr->protevil == 0) msg_print ("You no longer feel safe from evil."); } /* Invulnerability */ if (f_ptr->invuln > 0) { if ((PY_INVULN & f_ptr->status) == 0) { f_ptr->status |= PY_INVULN; disturb (0, 0); py.misc.pac += 100; py.misc.dis_ac += 100; prt_pac(); msg_print("Your skin turns into steel!"); } f_ptr->invuln--; if (f_ptr->invuln == 0) { #ifdef ATARIST_MWC f_ptr->status &= ~(holder = PY_INVULN); #else f_ptr->status &= ~PY_INVULN; #endif disturb (0, 0); py.misc.pac -= 100; py.misc.dis_ac -= 100; prt_pac(); msg_print("Your skin returns to normal."); } } /* Blessed */ if (f_ptr->blessed > 0) { if ((PY_BLESSED & f_ptr->status) == 0) { f_ptr->status |= PY_BLESSED; disturb (0, 0); p_ptr->bth += 5; p_ptr->bthb+= 5; p_ptr->pac += 2; p_ptr->dis_ac+= 2; msg_print("You feel righteous!"); prt_pac(); } f_ptr->blessed--; if (f_ptr->blessed == 0) { #ifdef ATARIST_MWC f_ptr->status &= ~(holder = PY_BLESSED); #else f_ptr->status &= ~PY_BLESSED; #endif disturb (0, 0); p_ptr->bth -= 5; p_ptr->bthb-= 5; p_ptr->pac -= 2; p_ptr->dis_ac -= 2; msg_print("The prayer has expired."); prt_pac(); } } /* Resist Heat */ if (f_ptr->resist_heat > 0) { f_ptr->resist_heat--; if (f_ptr->resist_heat == 0) msg_print ("You no longer feel safe from flame."); } /* Resist Cold */ if (f_ptr->resist_cold > 0) { f_ptr->resist_cold--; if (f_ptr->resist_cold == 0) msg_print ("You no longer feel safe from cold."); } /* Detect Invisible */ if (f_ptr->detect_inv > 0) { #ifdef ATARIST_MWC if (((holder = PY_DET_INV) & f_ptr->status) == 0) #else if ((PY_DET_INV & f_ptr->status) == 0) #endif { #ifdef ATARIST_MWC f_ptr->status |= holder; #else f_ptr->status |= PY_DET_INV; #endif f_ptr->see_inv = TRUE; /* light but don't move creatures */ creatures (FALSE); } f_ptr->detect_inv--; if (f_ptr->detect_inv == 0) { #ifdef ATARIST_MWC f_ptr->status &= ~holder; #else f_ptr->status &= ~PY_DET_INV; #endif /* may still be able to see_inv if wearing magic item */ calc_bonuses(); /* unlight but don't move creatures */ creatures (FALSE); } } /* Timed infra-vision */ if (f_ptr->tim_infra > 0) { #ifdef ATARIST_MWC if (((holder = PY_TIM_INFRA) & f_ptr->status) == 0) #else if ((PY_TIM_INFRA & f_ptr->status) == 0) #endif { #ifdef ATARIST_MWC f_ptr->status |= holder; #else f_ptr->status |= PY_TIM_INFRA; #endif f_ptr->see_infra++; /* light but don't move creatures */ creatures (FALSE); } f_ptr->tim_infra--; if (f_ptr->tim_infra == 0) { #ifdef ATARIST_MWC f_ptr->status &= ~holder; #else f_ptr->status &= ~PY_TIM_INFRA; #endif f_ptr->see_infra--; /* unlight but don't move creatures */ creatures (FALSE); } } /* Word-of-Recall Note: Word-of-Recall is a delayed action */ if (f_ptr->word_recall > 0) if (f_ptr->word_recall == 1) { new_level_flag = TRUE; f_ptr->paralysis++; f_ptr->word_recall = 0; if (dun_level > 0) { dun_level = 0; msg_print("You feel yourself yanked upwards!"); } else if (py.misc.max_dlv != 0) { dun_level = py.misc.max_dlv; msg_print("You feel yourself yanked downwards!"); } } else f_ptr->word_recall--; /* Random teleportation */ if ((py.flags.teleport) && (randint(100) == 1)) { disturb (0, 0); teleport(40); } /* See if we are too weak to handle the weapon or pack. -CJS- */ #ifdef ATARIST_MWC if (py.flags.status & (holder = PY_STR_WGT)) #else if (py.flags.status & PY_STR_WGT) #endif check_strength(); if (py.flags.status & PY_STUDY) prt_study(); #ifdef ATARIST_MWC if (py.flags.status & (holder = PY_SPEED)) #else if (py.flags.status & PY_SPEED) #endif { #ifdef ATARIST_MWC py.flags.status &= ~holder; #else py.flags.status &= ~PY_SPEED; #endif prt_speed(); } #ifdef ATARIST_MWC if ((py.flags.status & (holder = PY_PARALYSED)) && (py.flags.paralysis < 1)) #else if ((py.flags.status & PY_PARALYSED) && (py.flags.paralysis < 1)) #endif { prt_state(); #ifdef ATARIST_MWC py.flags.status &= ~holder; #else py.flags.status &= ~PY_PARALYSED; #endif } else if (py.flags.paralysis > 0) { prt_state(); #ifdef ATARIST_MWC py.flags.status |= (holder = PY_PARALYSED); #else py.flags.status |= PY_PARALYSED; #endif } else if (py.flags.rest != 0) prt_state(); #ifdef ATARIST_MWC if ((py.flags.status & (holder = PY_ARMOR)) != 0) #else if ((py.flags.status & PY_ARMOR) != 0) #endif { prt_pac(); #ifdef ATARIST_MWC py.flags.status &= ~holder; #else py.flags.status &= ~PY_ARMOR; #endif } #ifdef ATARIST_MWC if ((py.flags.status & (holder = PY_STATS)) != 0) #else if ((py.flags.status & PY_STATS) != 0) #endif { for (i = 0; i < 6; i++) #ifdef ATARIST_MWC if (((holder = PY_STR) << i) & py.flags.status) #else if ((PY_STR << i) & py.flags.status) #endif prt_stat(i); #ifdef ATARIST_MWC py.flags.status &= ~(holder = PY_STATS); #else py.flags.status &= ~PY_STATS; #endif } #ifdef ATARIST_MWC if (py.flags.status & (holder = PY_HP)) #else if (py.flags.status & PY_HP) #endif { prt_mhp(); prt_chp(); #ifdef ATARIST_MWC py.flags.status &= ~holder; #else py.flags.status &= ~PY_HP; #endif } #ifdef ATARIST_MWC if (py.flags.status & (holder = PY_MANA)) #else if (py.flags.status & PY_MANA) #endif { prt_cmana(); #ifdef ATARIST_MWC py.flags.status &= ~holder; #else py.flags.status &= ~PY_MANA; #endif } /* Allow for a slim chance of detect enchantment -CJS- */ /* for 1st level char, check once every 2160 turns for 40th level char, check once every 416 turns */ if (((turn & 0xF) == 0) && (f_ptr->confused == 0) && (randint((int)(10 + 750 / (5 + py.misc.lev))) == 1)) { vtype tmp_str; for (i = 0; i < INVEN_ARRAY_SIZE; i++) { if (i == inven_ctr) i = 22; i_ptr = &inventory[i]; /* if in inventory, succeed 1 out of 50 times, if in equipment list, success 1 out of 10 times */ if ((i_ptr->tval != TV_NOTHING) && enchanted(i_ptr) && (randint(i < 22 ? 50 : 10) == 1)) { extern char *describe_use(); (void) sprintf(tmp_str, "There's something about what you are %s...", describe_use(i)); disturb(0, 0); msg_print(tmp_str); add_inscribe(i_ptr, ID_MAGIK); } } } /* Check the state of the monster list, and delete some monsters if the monster list is nearly full. This helps to avoid problems in creature.c when monsters try to multiply. Compact_monsters() is much more likely to succeed if called from here, than if called from within creatures(). */ if (MAX_MALLOC - mfptr < 10) (void) compact_monsters (); if ((py.flags.paralysis < 1) && /* Accept a command? */ (py.flags.rest == 0) && (!death)) /* Accept a command and execute it */ { do { #ifdef ATARIST_MWC if (py.flags.status & (holder = PY_REPEAT)) #else if (py.flags.status & PY_REPEAT) #endif prt_state (); default_dir = FALSE; free_turn_flag = FALSE; if (find_flag) { find_run(); find_count--; if (find_count == 0) end_find(); put_qio(); } else if (doing_inven) inven_command (doing_inven); else { /* move the cursor to the players character */ move_cursor_relative (char_row, char_col); if (command_count > 0) { msg_flag = FALSE; default_dir = TRUE; } else { msg_flag = FALSE; #ifdef MAC unloadsegments(); enablesavecmd(TRUE); command = inkeydir(); enablesavecmd(FALSE); #else command = inkey(); #endif i = 0; /* Get a count for a command. */ if ((rogue_like_commands && command >= '0' && command <= '9') || (!rogue_like_commands && command == '#')) { char tmp[8]; prt("Repeat count:", 0, 0); if (command == '#') command = '0'; i = 0; while (TRUE) { if (command == DELETE || command == CTRL('H')) { i = i / 10; (void) sprintf(tmp, "%d", i); prt (tmp, 0, 14); } else if (command >= '0' && command <= '9') { if (i > 99) bell (); else { i = i * 10 + command - '0'; (void) sprintf (tmp, "%d", i); prt (tmp, 0, 14); } } else break; #ifdef MAC command = inkeydir(); #else command = inkey(); #endif } if (i == 0) { i = 99; (void) sprintf (tmp, "%d", i); prt (tmp, 0, 14); } /* a special hack to allow numbers as commands */ if (command == ' ') { prt ("Command:", 0, 20); #ifdef MAC command = inkeydir(); #else command = inkey(); #endif } } /* Another way of typing control codes -CJS- */ if (command == '^') { if (command_count > 0) prt_state(); if (get_com("Control-", &command)) { if (command >= 'A' && command <= 'Z') command -= 'A' - 1; else if (command >= 'a' && command <= 'z') command -= 'a' - 1; else { msg_print("Type ^ for a control char"); command = ' '; } } else command = ' '; } /* move cursor to player char again, in case it moved */ move_cursor_relative (char_row, char_col); /* Commands are always converted to rogue form. -CJS- */ if (rogue_like_commands == FALSE) command = original_commands (command); if (i > 0) { if (!valid_countcommand(command)) { free_turn_flag = TRUE; msg_print ("Invalid command with a count."); command = ' '; } else { command_count = i; prt_state (); } } } /* Flash the message line. */ erase_line(MSG_LINE, 0); move_cursor_relative(char_row, char_col); put_qio(); do_command (command); /* Find is counted differently, as the command changes. */ if (find_flag) { find_count = command_count - 1; command_count = 0; } else if (free_turn_flag) command_count = 0; else if (command_count) command_count--; } /* End of commands */ } while (free_turn_flag && !new_level_flag && !eof_flag); } else { /* if paralyzed, resting, or dead, flush output */ /* but first move the cursor onto the player, for aesthetics */ move_cursor_relative (char_row, char_col); put_qio (); } /* Teleport? */ if (teleport_flag) teleport(100); /* Move the creatures */ if (!new_level_flag) creatures(TRUE); /* Exit when new_level_flag is set */ } while (!new_level_flag && !eof_flag); } static char original_commands(com_val) char com_val; { int dir_val; switch(com_val) { case CTRL('K'): /*^K = exit */ com_val = 'Q'; break; case CTRL('J'): case CTRL('M'): com_val = '+'; break; case CTRL('P'): /*^P = repeat */ case CTRL('W'): /*^W = password*/ case CTRL('X'): /*^X = save */ case CTRL('V'): /*^V = view license */ case ' ': case '!': case '$': break; case '.': if (get_dir(CNIL, &dir_val)) switch (dir_val) { case 1: com_val = 'B'; break; case 2: com_val = 'J'; break; case 3: com_val = 'N'; break; case 4: com_val = 'H'; break; case 6: com_val = 'L'; break; case 7: com_val = 'Y'; break; case 8: com_val = 'K'; break; case 9: com_val = 'U'; break; default: com_val = ' '; break; } else com_val = ' '; break; case '/': case '<': case '>': case '-': case '=': case '{': case '?': case 'A': break; case '1': com_val = 'b'; break; case '2': com_val = 'j'; break; case '3': com_val = 'n'; break; case '4': com_val = 'h'; break; case '5': /* Rest one turn */ com_val = '.'; break; case '6': com_val = 'l'; break; case '7': com_val = 'y'; break; case '8': com_val = 'k'; break; case '9': com_val = 'u'; break; case 'B': com_val = 'f'; break; case 'C': case 'D': case 'E': case 'F': case 'G': break; case 'L': com_val = 'W'; break; case 'M': break; case 'R': break; case 'S': com_val = '#'; break; case 'T': if (get_dir(CNIL, &dir_val)) switch (dir_val) { case 1: com_val = CTRL('B'); break; case 2: com_val = CTRL('J'); break; case 3: com_val = CTRL('N'); break; case 4: com_val = CTRL('H'); break; case 6: com_val = CTRL('L'); break; case 7: com_val = CTRL('Y'); break; case 8: com_val = CTRL('K'); break; case 9: com_val = CTRL('U'); break; default: com_val = ' '; break; } else com_val = ' '; break; case 'V': break; case 'a': com_val = 'z'; break; case 'b': com_val = 'P'; break; case 'c': case 'd': case 'e': break; case 'f': com_val = 't'; break; case 'h': com_val = '?'; break; case 'i': break; case 'j': com_val = 'S'; break; case 'l': com_val = 'x'; break; case 'm': case 'o': case 'p': case 'q': case 'r': case 's': break; case 't': com_val = 'T'; break; case 'u': com_val = 'Z'; break; case 'v': case 'w': break; case 'x': com_val = 'X'; break; /* wizard mode commands follow */ case CTRL('A'): /*^A = cure all */ break; case CTRL('B'): /*^B = objects */ com_val = CTRL('O'); break; case CTRL('D'): /*^D = up/down */ break; case CTRL('H'): /*^H = wizhelp */ com_val = '\\'; break; case CTRL('I'): /*^I = identify*/ break; case CTRL('L'): /*^L = wizlight*/ com_val = '*'; break; case ':': case CTRL('T'): /*^T = teleport*/ case CTRL('E'): /*^E = wizchar */ case CTRL('F'): /*^F = genocide*/ case CTRL('G'): /*^G = treasure*/ case '@': case '+': break; case CTRL('U'): /*^U = summon */ com_val = '&'; break; default: com_val = '~'; /* Anything illegal. */ break; } return com_val; } static void do_command(com_val) char com_val; { int dir_val, do_pickup; int y, x, i, j; vtype out_val, tmp_str; register struct flags *f_ptr; /* hack for move without pickup. Map '-' to a movement command. */ if (com_val == '-') { do_pickup = FALSE; i = command_count; if (get_dir(CNIL, &dir_val)) { command_count = i; switch (dir_val) { case 1: com_val = 'b'; break; case 2: com_val = 'j'; break; case 3: com_val = 'n'; break; case 4: com_val = 'h'; break; case 6: com_val = 'l'; break; case 7: com_val = 'y'; break; case 8: com_val = 'k'; break; case 9: com_val = 'u'; break; default: com_val = '~'; break; } } else com_val = ' '; } else do_pickup = TRUE; switch(com_val) { case 'Q': /* (Q)uit (^K)ill */ flush(); if (get_check("Do you really want to quit?")) { new_level_flag = TRUE; death = TRUE; (void) strcpy(died_from, "Quitting"); } free_turn_flag = TRUE; break; case CTRL('P'): /* (^P)revious message. */ if (command_count > 0) { i = command_count; if (i > MAX_SAVE_MSG) i = MAX_SAVE_MSG; command_count = 0; } else if (last_command != CTRL('P')) i = 1; else i = MAX_SAVE_MSG; j = last_msg; if (i > 1) { save_screen(); x = i; while (i > 0) { i--; prt(old_msg[j], i, 0); if (j == 0) j = MAX_SAVE_MSG-1; else j--; } erase_line (x, 0); pause_line(x); restore_screen(); } else { /* Distinguish real and recovered messages with a '>'. -CJS- */ put_buffer(">", 0, 0); prt(old_msg[j], 0, 1); } free_turn_flag = TRUE; break; case CTRL('V'): /* (^V)iew license */ helpfile(MORIA_GPL); free_turn_flag = TRUE; break; case CTRL('W'): /* (^W)izard mode */ if (wizard) { wizard = FALSE; msg_print("Wizard mode off."); } else if (enter_wiz_mode()) msg_print("Wizard mode on."); prt_winner(); free_turn_flag = TRUE; break; case CTRL('X'): /* e(^X)it and save */ if (total_winner) { msg_print("You are a Total Winner, your character must be retired."); if (rogue_like_commands) msg_print("Use 'Q' to when you are ready to quit."); else msg_print ("Use -K when you are ready to quit."); } else { (void) strcpy (died_from, "(saved)"); msg_print ("Saving game..."); #ifdef MAC if (save_char (TRUE)) exit_game(); #else if (save_char ()) exit_game(); #endif (void) strcpy (died_from, "(alive and well)"); } free_turn_flag = TRUE; break; case '=': /* (=) set options */ save_screen(); set_options(); restore_screen(); free_turn_flag = TRUE; break; case '{': /* ({) inscribe an object */ scribe_object (); free_turn_flag = TRUE; break; case '!': /* (!) escape to the shell */ case '$': #ifdef SECURE msg_print("Sorry, inferior shells are not allowed from Moria."); #else shell_out(); #endif free_turn_flag = TRUE; break; case ESCAPE: /* (ESC) do nothing. */ case ' ': /* (space) do nothing. */ free_turn_flag = TRUE; break; case 'b': /* (b) down, left (1) */ move_char(1, do_pickup); break; case 'j': /* (j) down (2) */ move_char(2, do_pickup); break; case 'n': /* (n) down, right (3) */ move_char(3, do_pickup); break; case 'h': /* (h) left (4) */ move_char(4, do_pickup); break; case 'l': /* (l) right (6) */ move_char(6, do_pickup); break; case 'y': /* (y) up, left (7) */ move_char(7, do_pickup); break; case 'k': /* (k) up (8) */ move_char(8, do_pickup); break; case 'u': /* (u) up, right (9) */ move_char(9, do_pickup); break; case 'B': /* (B) run down, left (. 1) */ find_init(1); break; case 'J': /* (J) run down (. 2) */ find_init(2); break; case 'N': /* (N) run down, right (. 3) */ find_init(3); break; case 'H': /* (H) run left (. 4) */ find_init(4); break; case 'L': /* (L) run right (. 6) */ find_init(6); break; case 'Y': /* (Y) run up, left (. 7) */ find_init(7); break; case 'K': /* (K) run up (. 8) */ find_init(8); break; case 'U': /* (U) run up, right (. 9) */ find_init(9); break; case '/': /* (/) identify a symbol */ ident_char(); free_turn_flag = TRUE; break; case '.': /* (.) stay in one place (5) */ move_char (5, do_pickup); if (command_count > 1) { command_count--; rest(); } break; case '<': /* (<) go down a staircase */ go_up(); break; case '>': /* (>) go up a staircase */ go_down(); break; case '?': /* (?) help with commands */ if (rogue_like_commands) helpfile(MORIA_HELP); else helpfile(MORIA_ORIG_HELP); free_turn_flag = TRUE; break; case 'f': /* (f)orce (B)ash */ bash(); break; case 'C': /* (C)haracter description */ save_screen(); change_name(); restore_screen(); free_turn_flag = TRUE; break; case 'D': /* (D)isarm trap */ disarm_trap(); break; case 'E': /* (E)at food */ eat(); break; case 'F': /* (F)ill lamp */ refill_lamp(); break; case 'G': /* (G)ain magic spells */ gain_spells(); break; case 'V': /* (V)iew scores */ if (last_command != 'V') i = TRUE; else i = FALSE; save_screen(); display_scores(i); restore_screen(); free_turn_flag = TRUE; break; case 'W': /* (W)here are we on the map (L)ocate on map */ if ((py.flags.blind > 0) || no_light()) msg_print("You can't see your map."); else { int cy, cx, p_y, p_x; y = char_row; x = char_col; if (get_panel(y, x, TRUE)) prt_map(); cy = panel_row; cx = panel_col; for(;;) { p_y = panel_row; p_x = panel_col; if (p_y == cy && p_x == cx) tmp_str[0] = '\0'; else (void) sprintf(tmp_str, "%s%s of", p_y < cy ? " North" : p_y > cy ? " South" : "", p_x < cx ? " West" : p_x > cx ? " East" : ""); (void) sprintf(out_val, "Map sector [%d,%d], which is%s your sector. Look which direction?", p_y, p_x, tmp_str); if (!get_dir(out_val, &dir_val)) break; /* -CJS- // Should really use the move function, but what the hell. This // is nicer, as it moves exactly to the same place in another // section. The direction calculation is not intuitive. Sorry. */ for(;;){ x += ((dir_val-1)%3 - 1) * SCREEN_WIDTH/2; y -= ((dir_val-1)/3 - 1) * SCREEN_HEIGHT/2; if (x < 0 || y < 0 || x >= cur_width || y >= cur_width) { msg_print("You've gone past the end of your map."); x -= ((dir_val-1)%3 - 1) * SCREEN_WIDTH/2; y += ((dir_val-1)/3 - 1) * SCREEN_HEIGHT/2; break; } if (get_panel(y, x, TRUE)) { prt_map(); break; } } } /* Move to a new panel - but only if really necessary. */ if (get_panel(char_row, char_col, FALSE)) prt_map(); } free_turn_flag = TRUE; break; case 'R': /* (R)est a while */ rest(); break; case '#': /* (#) search toggle (S)earch toggle */ if (py.flags.status & PY_SEARCH) search_off(); else search_on(); free_turn_flag = TRUE; break; case CTRL('B'): /* (^B) tunnel down left (T 1) */ tunnel(1); break; case CTRL('M'): /* cr must be treated same as lf. */ case CTRL('J'): /* (^J) tunnel down (T 2) */ tunnel(2); break; case CTRL('N'): /* (^N) tunnel down right (T 3) */ tunnel(3); break; case CTRL('H'): /* (^H) tunnel left (T 4) */ tunnel(4); break; case CTRL('L'): /* (^L) tunnel right (T 6) */ tunnel(6); break; case CTRL('Y'): /* (^Y) tunnel up left (T 7) */ tunnel(7); break; case CTRL('K'): /* (^K) tunnel up (T 8) */ tunnel(8); break; case CTRL('U'): /* (^U) tunnel up right (T 9) */ tunnel(9); break; case 'z': /* (z)ap a wand (a)im a wand */ aim(); break; case 'M': screen_map(); free_turn_flag = TRUE; break; case 'P': /* (P)eruse a book (B)rowse in a book */ examine_book(); free_turn_flag = TRUE; break; case 'c': /* (c)lose an object */ closeobject(); break; case 'd': /* (d)rop something */ inven_command('d'); break; case 'e': /* (e)quipment list */ inven_command('e'); break; case 't': /* (t)hrow something (f)ire something */ throw_object(); break; case 'i': /* (i)nventory list */ inven_command('i'); break; case 'S': /* (S)pike a door (j)am a door */ jamdoor(); break; case 'x': /* e(x)amine surrounds (l)ook about */ look(); free_turn_flag = TRUE; break; case 'm': /* (m)agic spells */ cast(); break; case 'o': /* (o)pen something */ openobject(); break; case 'p': /* (p)ray */ pray(); break; case 'q': /* (q)uaff */ quaff(); break; case 'r': /* (r)ead */ read_scroll(); break; case 's': /* (s)earch for a turn */ search(char_row, char_col, py.misc.srh); break; case 'T': /* (T)ake off something (t)ake off */ inven_command('t'); break; case 'Z': /* (Z)ap a staff (u)se a staff */ use(); break; case 'v': /* (v)ersion of game */ helpfile(MORIA_VER); free_turn_flag = TRUE; break; case 'w': /* (w)ear or wield */ inven_command('w'); break; case 'X': /* e(X)change weapons e(x)change */ inven_command('x'); break; default: if (wizard) { free_turn_flag = TRUE; /* Wizard commands are free moves*/ switch(com_val) { case CTRL('A'): /*^A = Cure all*/ (void) remove_curse(); (void) cure_blindness(); (void) cure_confusion(); (void) cure_poison(); (void) remove_fear(); (void) res_stat(A_STR); (void) res_stat(A_INT); (void) res_stat(A_WIS); (void) res_stat(A_CON); (void) res_stat(A_DEX); (void) res_stat(A_CHR); f_ptr = &py.flags; if (f_ptr->slow > 1) f_ptr->slow = 1; if (f_ptr->image > 1) f_ptr->image = 1; break; case CTRL('E'): /*^E = wizchar */ change_character(); erase_line(MSG_LINE, 0); break; case CTRL('F'): /*^F = genocide*/ (void) mass_genocide(); break; case CTRL('G'): /*^G = treasure*/ if (command_count > 0) { i = command_count; command_count = 0; } else i = 1; random_object(char_row, char_col, i); prt_map(); break; case CTRL('D'): /*^D = up/down */ if (command_count > 0) { if (command_count > 99) i = 0; else i = command_count; command_count = 0; } else { prt("Go to which level (0-99) ? ", 0, 0); i = -1; if (get_string(tmp_str, 0, 27, 10)) i = atoi(tmp_str); } if (i > -1) { dun_level = i; if (dun_level > 99) dun_level = 99; new_level_flag = TRUE; } else erase_line(MSG_LINE, 0); break; case CTRL('O'): /*^O = objects */ print_objects(); break; case '\\': /* \ wizard help */ if (rogue_like_commands) helpfile(MORIA_WIZ_HELP); else helpfile(MORIA_OWIZ_HELP); break; case CTRL('I'): /*^I = identify*/ (void) ident_spell(); break; case '*': wizard_light(); break; case ':': map_area(); break; case CTRL('T'): /*^T = teleport*/ teleport(100); break; case '+': if (command_count > 0) { py.misc.exp = command_count; command_count = 0; } else if (py.misc.exp == 0) py.misc.exp = 1; else py.misc.exp = py.misc.exp * 2; prt_experience(); break; case '&': /*& = summon */ y = char_row; x = char_col; (void) summon_monster(&y, &x, TRUE); creatures(FALSE); break; case '@': wizard_create(); break; default: if (rogue_like_commands) prt("Type '?' or '\\' for help.", 0, 0); else prt("Type '?' or ^H for help.", 0, 0); } } else { prt("Type '?' for help.", 0, 0); free_turn_flag = TRUE; } } last_command = com_val; } /* Check whether this command will accept a count. -CJS- */ static int valid_countcommand(c) char c; { switch(c) { case 'Q': case CTRL('W'): case CTRL('X'): case '=': case '{': case '/': case '<': case '>': case '?': case 'C': case 'E': case 'F': case 'G': case 'V': case '#': case 'z': case 'P': case 'c': case 'd': case 'e': case 't': case 'i': case 'x': case 'm': case 'p': case 'q': case 'r': case 'T': case 'Z': case 'v': case 'w': case 'W': case 'X': case CTRL('A'): case '\\': case CTRL('I'): case '*': case ':': case CTRL('T'): case CTRL('E'): case CTRL('F'): case CTRL('S'): case CTRL('Q'): return FALSE; case CTRL('P'): case ESCAPE: case ' ': case '-': case 'b': case 'f': case 'j': case 'n': case 'h': case 'l': case 'y': case 'k': case 'u': case '.': case 'B': case 'J': case 'N': case 'H': case 'L': case 'Y': case 'K': case 'U': case 'D': case 'R': case CTRL('Y'): case CTRL('K'): case CTRL('U'): case CTRL('L'): case CTRL('N'): case CTRL('J'): case CTRL('B'): case CTRL('H'): case 'S': case 'o': case 's': case CTRL('D'): case CTRL('G'): case '+': return TRUE; default: return FALSE; } } /* Regenerate hit points -RAK- */ static void regenhp(percent) int percent; { register struct misc *p_ptr; register int32 new_chp, new_chp_frac; int old_chp; p_ptr = &py.misc; old_chp = p_ptr->chp; new_chp = ((long)p_ptr->mhp) * percent + PLAYER_REGEN_HPBASE; p_ptr->chp += new_chp >> 16; /* div 65536 */ /* check for overflow */ if (p_ptr->chp < 0 && old_chp > 0) p_ptr->chp = MAX_SHORT; new_chp_frac = (new_chp & 0xFFFF) + p_ptr->chp_frac; /* mod 65536 */ if (new_chp_frac >= 0x10000L) { p_ptr->chp_frac = new_chp_frac - 0x10000L; p_ptr->chp++; } else p_ptr->chp_frac = new_chp_frac; /* must set frac to zero even if equal */ if (p_ptr->chp >= p_ptr->mhp) { p_ptr->chp = p_ptr->mhp; p_ptr->chp_frac = 0; } if (old_chp != p_ptr->chp) prt_chp(); } /* Regenerate mana points -RAK- */ static void regenmana(percent) int percent; { register struct misc *p_ptr; register int32 new_mana, new_mana_frac; int old_cmana; p_ptr = &py.misc; old_cmana = p_ptr->cmana; new_mana = ((long)p_ptr->mana) * percent + PLAYER_REGEN_MNBASE; p_ptr->cmana += new_mana >> 16; /* div 65536 */ /* check for overflow */ if (p_ptr->cmana < 0 && old_cmana > 0) p_ptr->cmana = MAX_SHORT; new_mana_frac = (new_mana & 0xFFFF) + p_ptr->cmana_frac; /* mod 65536 */ if (new_mana_frac >= 0x10000L) { p_ptr->cmana_frac = new_mana_frac - 0x10000L; p_ptr->cmana++; } else p_ptr->cmana_frac = new_mana_frac; /* must set frac to zero even if equal */ if (p_ptr->cmana >= p_ptr->mana) { p_ptr->cmana = p_ptr->mana; p_ptr->cmana_frac = 0; } if (old_cmana != p_ptr->cmana) prt_cmana(); } /* Is an item an enchanted weapon or armor and we don't know? -CJS- */ /* only returns true if it is a good enchantment */ static int enchanted (t_ptr) register inven_type *t_ptr; { #ifdef ATARIST_MWC int32u holder; #endif if (t_ptr->tval < TV_MIN_ENCHANT || t_ptr->tval > TV_MAX_ENCHANT #ifdef ATARIST_MWC || t_ptr->flags & (holder = TR_CURSED)) #else || t_ptr->flags & TR_CURSED) #endif return FALSE; if (known2_p(t_ptr)) return FALSE; if (t_ptr->ident & ID_MAGIK) return FALSE; if (t_ptr->tohit > 0 || t_ptr->todam > 0 || t_ptr->toac > 0) return TRUE; if ((0x4000107fL & t_ptr->flags) && t_ptr->p1 > 0) return TRUE; if (0x07ffe980L & t_ptr->flags) return TRUE; return FALSE; } /* Examine a Book -RAK- */ static void examine_book() { int32u j; int i, k, item_val, flag; int spell_index[31]; register inven_type *i_ptr; register spell_type *s_ptr; if (!find_range(TV_MAGIC_BOOK, TV_PRAYER_BOOK, &i, &k)) msg_print("You are not carrying any books."); else if (py.flags.blind > 0) msg_print("You can't see to read your spell book!"); else if (no_light()) msg_print("You have no light to read by."); else if (py.flags.confused > 0) msg_print("You are too confused."); else if (get_item(&item_val, "Which Book?", i, k, CNIL, CNIL)) { flag = TRUE; i_ptr = &inventory[item_val]; if (class[py.misc.pclass].spell == MAGE) { if (i_ptr->tval != TV_MAGIC_BOOK) flag = FALSE; } else if (class[py.misc.pclass].spell == PRIEST) { if (i_ptr->tval != TV_PRAYER_BOOK) flag = FALSE; } else flag = FALSE; if (!flag) msg_print("You do not understand the language."); else { i = 0; j = inventory[item_val].flags; while (j) { k = bit_pos(&j); s_ptr = &magic_spell[py.misc.pclass-1][k]; if (s_ptr->slevel < 99) { spell_index[i] = k; i++; } } save_screen(); print_spells(spell_index, i, TRUE, -1); pause_line(0); restore_screen(); } } } /* Go up one level -RAK- */ static void go_up() { register cave_type *c_ptr; register int no_stairs = FALSE; c_ptr = &cave[char_row][char_col]; if (c_ptr->tptr != 0) if (t_list[c_ptr->tptr].tval == TV_UP_STAIR) { dun_level--; new_level_flag = TRUE; msg_print("You enter a maze of up staircases."); msg_print("You pass through a one-way door."); } else no_stairs = TRUE; else no_stairs = TRUE; if (no_stairs) { msg_print("I see no up staircase here."); free_turn_flag = TRUE; } } /* Go down one level -RAK- */ static void go_down() { register cave_type *c_ptr; register int no_stairs = FALSE; c_ptr = &cave[char_row][char_col]; if (c_ptr->tptr != 0) if (t_list[c_ptr->tptr].tval == TV_DOWN_STAIR) { dun_level++; new_level_flag = TRUE; msg_print("You enter a maze of down staircases."); msg_print("You pass through a one-way door."); } else no_stairs = TRUE; else no_stairs = TRUE; if (no_stairs) { msg_print("I see no down staircase here."); free_turn_flag = TRUE; } } /* Jam a closed door -RAK- */ static void jamdoor() { int y, x, dir, i, j; register cave_type *c_ptr; register inven_type *t_ptr, *i_ptr; char tmp_str[80]; free_turn_flag = TRUE; y = char_row; x = char_col; if (get_dir(CNIL, &dir)) { (void) mmove(dir, &y, &x); c_ptr = &cave[y][x]; if (c_ptr->tptr != 0) { t_ptr = &t_list[c_ptr->tptr]; if (t_ptr->tval == TV_CLOSED_DOOR) if (c_ptr->cptr == 0) { if (find_range(TV_SPIKE, TV_NEVER, &i, &j)) { free_turn_flag = FALSE; count_msg_print("You jam the door with a spike."); if (t_ptr->p1 > 0) t_ptr->p1 = -t_ptr->p1; /* Make locked to stuck. */ /* Successive spikes have a progressively smaller effect. Series is: 0 20 30 37 43 48 52 56 60 64 67 70 ... */ t_ptr->p1 -= 1 + 190 / (10 - t_ptr->p1); i_ptr = &inventory[i]; if (i_ptr->number > 1) { i_ptr->number--; inven_weight -= i_ptr->weight; } else inven_destroy(i); } else msg_print("But you have no spikes."); } else { free_turn_flag = FALSE; (void) sprintf(tmp_str, "The %s is in your way!", c_list[m_list[c_ptr->cptr].mptr].name); msg_print(tmp_str); } else if (t_ptr->tval == TV_OPEN_DOOR) msg_print("The door must be closed first."); else msg_print("That isn't a door!"); } else msg_print("That isn't a door!"); } } /* Refill the players lamp -RAK- */ static void refill_lamp() { int i, j; register int k; register inven_type *i_ptr; free_turn_flag = TRUE; k = inventory[INVEN_LIGHT].subval; if (k != 0) msg_print("But you are not using a lamp."); else if (!find_range(TV_FLASK, TV_NEVER, &i, &j)) msg_print("You have no oil."); else { free_turn_flag = FALSE; i_ptr = &inventory[INVEN_LIGHT]; i_ptr->p1 += inventory[i].p1; if (i_ptr->p1 > OBJ_LAMP_MAX) { i_ptr->p1 = OBJ_LAMP_MAX; msg_print ("Your lamp overflows, spilling oil on the ground."); msg_print("Your lamp is full."); } else if (i_ptr->p1 > OBJ_LAMP_MAX/2) msg_print ("Your lamp is more than half full."); else if (i_ptr->p1 == OBJ_LAMP_MAX/2) msg_print ("Your lamp is half full."); else msg_print ("Your lamp is less than half full."); desc_remain(i); inven_destroy(i); } } moria-5.6.debian.1/source/save.c0000644000175000017500000012237011074756544014607 0ustar pjbpjb/* source/save.c: save and restore games and monster memory info Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ /* For debugging the savefile code on systems with broken compilers. */ #if 0 #define DEBUG(x) x #else #define DEBUG(x) #endif #include #ifdef __TURBOC__ #include #endif /* __TURBOC__ */ #include "config.h" #include "constant.h" #include "types.h" #ifndef USG /* stuff only needed for Berkeley UNIX */ #include #include #include #endif #ifdef VMS #include #include #else #ifdef USG #ifndef ATARIST_MWC #include #ifndef ATARIST_TC #include #endif #else #include "string.h" #endif #else #include #endif #endif /* This must be included after fcntl.h, which has a prototype for `open' on some systems. Otherwise, the `open' prototype conflicts with the `topen' declaration. */ #include "externs.h" #ifdef ATARIST_TC #include #endif DEBUG(static FILE *logfile); #if defined(LINT_ARGS) static int sv_write(void); static void wr_byte(int8u); static void wr_short(int16u); static void wr_long(int32u); static void wr_bytes(int8u *, int); static void wr_string(char *); static void wr_shorts(int16u *, int); static void wr_item(inven_type *); static void wr_monster(monster_type *); static void rd_byte(int8u *); static void rd_short(int16u *); static void rd_long(int32u *); static void rd_bytes(int8u *, int); static void rd_string(char *); static void rd_shorts(int16u *, int); static void rd_item(inven_type *); static void rd_monster(monster_type *); #else static int sv_write(); static void wr_byte(); static void wr_short(); static void wr_long(); static void wr_bytes(); static void wr_string(); static void wr_shorts(); static void wr_item(); static void wr_monster(); static void rd_byte(); static void rd_short(); static void rd_long(); static void rd_bytes(); static void rd_string(); static void rd_shorts(); static void rd_item(); static void rd_monster(); #endif #if !defined(ATARIST_MWC) #ifdef MAC #include #else long time(); #endif #else char *malloc(); #endif /* these are used for the save file, to avoid having to pass them to every procedure */ static FILE *fileptr; static int8u xor_byte; static int from_savefile; /* can overwrite old savefile when save */ static int32u start_time; /* time that play started */ /* This save package was brought to by -JWT- and -RAK- and has been completely rewritten for UNIX by -JEW- */ /* and has been completely rewritten again by -CJS- */ /* and completely rewritten again! for portability by -JEW- */ static int sv_write() { int32u l; register int i, j; int count; int8u char_tmp, prev_char; register cave_type *c_ptr; register recall_type *r_ptr; struct stats *s_ptr; register struct flags *f_ptr; store_type *st_ptr; struct misc *m_ptr; #if defined(MSDOS) || defined(ATARI_ST) inven_type *t_ptr; #endif /* clear the death flag when creating a HANGUP save file, so that player can see tombstone when restart */ if (eof_flag) death = FALSE; l = 0; if (find_cut) l |= 0x1; if (find_examine) l |= 0x2; if (find_prself) l |= 0x4; if (find_bound) l |= 0x8; if (prompt_carry_flag) l |= 0x10; if (rogue_like_commands) l |= 0x20; if (show_weight_flag) l |= 0x40; if (highlight_seams) l |= 0x80; if (find_ignore_doors) l |= 0x100; if (sound_beep_flag) l |= 0x200; if (display_counts) l |= 0x400; if (death) l |= 0x80000000L; /* Sign bit */ if (total_winner) l |= 0x40000000L; for (i = 0; i < MAX_CREATURES; i++) { r_ptr = &c_recall[i]; if (r_ptr->r_cmove || r_ptr->r_cdefense || r_ptr->r_kills || r_ptr->r_spells || r_ptr->r_deaths || r_ptr->r_attacks[0] || r_ptr->r_attacks[1] || r_ptr->r_attacks[2] || r_ptr->r_attacks[3]) { wr_short((int16u)i); wr_long(r_ptr->r_cmove); wr_long(r_ptr->r_spells); wr_short(r_ptr->r_kills); wr_short(r_ptr->r_deaths); wr_short(r_ptr->r_cdefense); wr_byte(r_ptr->r_wake); wr_byte(r_ptr->r_ignore); wr_bytes(r_ptr->r_attacks, MAX_MON_NATTACK); } } wr_short((int16u)0xFFFF); /* sentinel to indicate no more monster info */ wr_long(l); m_ptr = &py.misc; wr_string(m_ptr->name); wr_byte(m_ptr->male); wr_long((int32u)m_ptr->au); wr_long((int32u)m_ptr->max_exp); wr_long((int32u)m_ptr->exp); wr_short(m_ptr->exp_frac); wr_short(m_ptr->age); wr_short(m_ptr->ht); wr_short(m_ptr->wt); wr_short(m_ptr->lev); wr_short(m_ptr->max_dlv); wr_short((int16u)m_ptr->srh); wr_short((int16u)m_ptr->fos); wr_short((int16u)m_ptr->bth); wr_short((int16u)m_ptr->bthb); wr_short((int16u)m_ptr->mana); wr_short((int16u)m_ptr->mhp); wr_short((int16u)m_ptr->ptohit); wr_short((int16u)m_ptr->ptodam); wr_short((int16u)m_ptr->pac); wr_short((int16u)m_ptr->ptoac); wr_short((int16u)m_ptr->dis_th); wr_short((int16u)m_ptr->dis_td); wr_short((int16u)m_ptr->dis_ac); wr_short((int16u)m_ptr->dis_tac); wr_short((int16u)m_ptr->disarm); wr_short((int16u)m_ptr->save); wr_short((int16u)m_ptr->sc); wr_short((int16u)m_ptr->stl); wr_byte(m_ptr->pclass); wr_byte(m_ptr->prace); wr_byte(m_ptr->hitdie); wr_byte(m_ptr->expfact); wr_short((int16u)m_ptr->cmana); wr_short(m_ptr->cmana_frac); wr_short((int16u)m_ptr->chp); wr_short(m_ptr->chp_frac); for (i = 0; i < 4; i++) wr_string (m_ptr->history[i]); s_ptr = &py.stats; wr_bytes(s_ptr->max_stat, 6); wr_bytes(s_ptr->cur_stat, 6); wr_shorts((int16u *)s_ptr->mod_stat, 6); wr_bytes(s_ptr->use_stat, 6); f_ptr = &py.flags; wr_long(f_ptr->status); wr_short((int16u)f_ptr->rest); wr_short((int16u)f_ptr->blind); wr_short((int16u)f_ptr->paralysis); wr_short((int16u)f_ptr->confused); wr_short((int16u)f_ptr->food); wr_short((int16u)f_ptr->food_digested); wr_short((int16u)f_ptr->protection); wr_short((int16u)f_ptr->speed); wr_short((int16u)f_ptr->fast); wr_short((int16u)f_ptr->slow); wr_short((int16u)f_ptr->afraid); wr_short((int16u)f_ptr->poisoned); wr_short((int16u)f_ptr->image); wr_short((int16u)f_ptr->protevil); wr_short((int16u)f_ptr->invuln); wr_short((int16u)f_ptr->hero); wr_short((int16u)f_ptr->shero); wr_short((int16u)f_ptr->blessed); wr_short((int16u)f_ptr->resist_heat); wr_short((int16u)f_ptr->resist_cold); wr_short((int16u)f_ptr->detect_inv); wr_short((int16u)f_ptr->word_recall); wr_short((int16u)f_ptr->see_infra); wr_short((int16u)f_ptr->tim_infra); wr_byte(f_ptr->see_inv); wr_byte(f_ptr->teleport); wr_byte(f_ptr->free_act); wr_byte(f_ptr->slow_digest); wr_byte(f_ptr->aggravate); wr_byte(f_ptr->fire_resist); wr_byte(f_ptr->cold_resist); wr_byte(f_ptr->acid_resist); wr_byte(f_ptr->regenerate); wr_byte(f_ptr->lght_resist); wr_byte(f_ptr->ffall); wr_byte(f_ptr->sustain_str); wr_byte(f_ptr->sustain_int); wr_byte(f_ptr->sustain_wis); wr_byte(f_ptr->sustain_con); wr_byte(f_ptr->sustain_dex); wr_byte(f_ptr->sustain_chr); wr_byte(f_ptr->confuse_monster); wr_byte(f_ptr->new_spells); wr_short((int16u)missile_ctr); wr_long((int32u)turn); wr_short((int16u)inven_ctr); for (i = 0; i < inven_ctr; i++) wr_item(&inventory[i]); for (i = INVEN_WIELD; i < INVEN_ARRAY_SIZE; i++) wr_item(&inventory[i]); wr_short((int16u)inven_weight); wr_short((int16u)equip_ctr); wr_long(spell_learned); wr_long(spell_worked); wr_long(spell_forgotten); wr_bytes(spell_order, 32); wr_bytes(object_ident, OBJECT_IDENT_SIZE); wr_long(randes_seed); wr_long(town_seed); wr_short((int16u)last_msg); for (i = 0; i < MAX_SAVE_MSG; i++) wr_string(old_msg[i]); /* this indicates 'cheating' if it is a one */ wr_short((int16u)panic_save); wr_short((int16u)total_winner); wr_short((int16u)noscore); wr_shorts(player_hp, MAX_PLAYER_LEVEL); for (i = 0; i < MAX_STORES; i++) { st_ptr = &store[i]; wr_long((int32u)st_ptr->store_open); wr_short((int16u)st_ptr->insult_cur); wr_byte(st_ptr->owner); wr_byte(st_ptr->store_ctr); wr_short(st_ptr->good_buy); wr_short(st_ptr->bad_buy); for (j = 0; j < st_ptr->store_ctr; j++) { wr_long((int32u)st_ptr->store_inven[j].scost); wr_item(&st_ptr->store_inven[j].sitem); } } /* save the current time in the savefile */ #ifdef MAC l = time((time_t *)0); #else l = time((long *)0); #endif if (l < start_time) { /* someone is messing with the clock!, assume that we have been playing for 1 day */ l = start_time + 86400L; } wr_long(l); /* starting with 5.2, put died_from string in savefile */ wr_string(died_from); /* starting with 5.2.2, put the max_score in the savefile */ l = total_points (); wr_long (l); /* starting with 5.2.2, put the birth_date in the savefile */ wr_long ((int32u) birth_date); /* only level specific info follows, this allows characters to be resurrected, the dungeon level info is not needed for a resurrection */ if (death) { if (ferror(fileptr) || fflush(fileptr) == EOF) return FALSE; return TRUE; } wr_short((int16u)dun_level); wr_short((int16u)char_row); wr_short((int16u)char_col); wr_short((int16u)mon_tot_mult); wr_short((int16u)cur_height); wr_short((int16u)cur_width); wr_short((int16u)max_panel_rows); wr_short((int16u)max_panel_cols); for (i = 0; i < MAX_HEIGHT; i++) for (j = 0; j < MAX_WIDTH; j++) { c_ptr = &cave[i][j]; if (c_ptr->cptr != 0) { wr_byte((int8u)i); wr_byte((int8u)j); wr_byte(c_ptr->cptr); } } wr_byte((int8u)0xFF); /* marks end of cptr info */ for (i = 0; i < MAX_HEIGHT; i++) for (j = 0; j < MAX_WIDTH; j++) { c_ptr = &cave[i][j]; if (c_ptr->tptr != 0) { wr_byte((int8u)i); wr_byte((int8u)j); wr_byte(c_ptr->tptr); } } wr_byte((int8u)0xFF); /* marks end of tptr info */ /* must set counter to zero, note that code may write out two bytes unnecessarily */ count = 0; prev_char = 0; for (i = 0; i < MAX_HEIGHT; i++) for (j = 0; j < MAX_WIDTH; j++) { c_ptr = &cave[i][j]; char_tmp = c_ptr->fval | (c_ptr->lr << 4) | (c_ptr->fm << 5) | (c_ptr->pl << 6) | (c_ptr->tl << 7); if (char_tmp != prev_char || count == MAX_UCHAR) { wr_byte((int8u)count); wr_byte(prev_char); prev_char = char_tmp; count = 1; } else count++; } /* save last entry */ wr_byte((int8u)count); wr_byte(prev_char); #if defined(MSDOS) || defined(ATARI_ST) /* must change graphics symbols for walls and floors back to default chars, this is necessary so that if the user changes the graphics line, the program will be able change all existing walls and floors to the new symbol */ /* Or if the user moves the savefile from one machine to another, we must have a consistent representation here. */ t_ptr = &t_list[tcptr - 1]; for (i = tcptr - 1; i >= MIN_TRIX; i--) { #ifdef MSDOS if (t_ptr->tchar == wallsym) t_ptr->tchar = '#'; #endif #ifdef ATARI_ST if (t_ptr->tchar == (unsigned char)240) t_ptr->tchar = '#'; #endif t_ptr--; } #endif wr_short((int16u)tcptr); for (i = MIN_TRIX; i < tcptr; i++) wr_item(&t_list[i]); wr_short((int16u)mfptr); for (i = MIN_MONIX; i < mfptr; i++) wr_monster(&m_list[i]); if (ferror(fileptr) || (fflush(fileptr) == EOF)) return FALSE; return TRUE; } #ifdef MAC /* Set up prior to actual save, do the save, then clean up */ /* Notice that Mac version of this function takes a parameter */ /* To do a "save as" set always_ask */ /* To do a "save" clear always_ask */ int save_char(always_ask) int always_ask; { int rc, already_set, proceed; int16 vrefnum; /* cannot rely on _save_char to do this because we may put up a dialog */ if (character_saved) return(TRUE); enablefilemenu(FALSE); already_set = getsavedefaults(savefile, &vrefnum); if (!already_set || always_ask) { /* Here if always_ask or user has not yet specified a save file */ /* User specifies a save file when he restarts a previous one */ sfposition(vrefnum); proceed = doputfile(death ? "Save memories as:" : "Save game as:", savefile, &vrefnum); } else proceed = TRUE; if (proceed) { changedirectory(vrefnum); rc = _save_char(savefile); restoredirectory(); } else rc = FALSE; if (rc) (void) setfileinfo(savefile, vrefnum, SAVE_FTYPE); enablefilemenu(TRUE); return(rc); } #else /* The Mac has different logic here -- See above */ int save_char() { int i; vtype temp; #ifdef SECURE bePlayer(); #endif while (!_save_char(savefile)) { (void) sprintf(temp, "Savefile '%s' fails.", savefile); msg_print(temp); i = 0; if (access(savefile, 0) < 0 || get_check("File exists. Delete old savefile?") == 0 || (i = unlink(savefile)) < 0) { if (i < 0) { (void) sprintf(temp, "Can't delete '%s'", savefile); msg_print(temp); } prt("New Savefile [ESC to give up]:", 0, 0); if (!get_string(temp, 0, 31, 45)) return FALSE; if (temp[0]) (void) strcpy(savefile, temp); } (void) sprintf(temp, "Saving with %s...", savefile); prt(temp, 0, 0); } #ifdef SECURE beGames(); #endif return TRUE; } #endif int _save_char(fnam) char *fnam; { vtype temp; register int ok, fd; int8u char_tmp; if (character_saved) return TRUE; /* Nothing to save. */ nosignals(); put_qio(); disturb (1, 0); /* Turn off resting and searching. */ change_speed(-pack_heavy); /* Fix the speed */ pack_heavy = 0; ok = FALSE; /* VMS files have version numbers, so don't worry about overwriting the old save file. */ #if !defined(ATARIST_MWC) && !defined(VMS) fd = -1; fileptr = NULL; /* Do not assume it has been init'ed */ #if defined(MAC) || defined(AMIGA) /* The Mac version automatically overwrites */ fd = open(fnam, O_RDWR|O_CREAT|O_TRUNC); #ifdef MAC macbeginwait (); #endif #else fd = open(fnam, O_RDWR|O_CREAT|O_EXCL, 0600); if (fd < 0 && access(fnam, 0) >= 0 && (from_savefile || (wizard && get_check("Can't make new savefile. Overwrite old?")))) { (void) chmod(fnam, 0600); fd = open(fnam, O_RDWR|O_TRUNC, 0600); } #endif if (fd >= 0) { (void) close(fd); #endif /* !ATARIST_MWC && !VMS */ /* GCC for atari st defines atarist */ #if defined(atarist) || defined(ATARI_ST) || defined(THINK_C) || defined(MSDOS) fileptr = fopen(savefile, "wb"); #else fileptr = fopen(savefile, "w"); #endif #if !defined(ATARIST_MWC) && !defined(VMS) } #endif DEBUG(logfile = fopen("IO_LOG", "a")); DEBUG(fprintf (logfile, "Saving data to %s\n", savefile)); if (fileptr != NULL) { xor_byte = 0; wr_byte((int8u)CUR_VERSION_MAJ); xor_byte = 0; wr_byte((int8u)CUR_VERSION_MIN); xor_byte = 0; wr_byte((int8u)PATCH_LEVEL); xor_byte = 0; char_tmp = randint(256) - 1; wr_byte(char_tmp); /* Note that xor_byte is now equal to char_tmp */ ok = sv_write(); DEBUG(fclose (logfile)); if (fclose(fileptr) == EOF) ok = FALSE; } #ifdef MAC macendwait (); #endif if (!ok) { if (fd >= 0) (void) unlink(fnam); signals(); if (fd >= 0) (void) sprintf(temp, "Error writing to file %s", fnam); else (void) sprintf(temp, "Can't create new file %s", fnam); msg_print(temp); return FALSE; } else character_saved = 1; turn = -1; signals(); return TRUE; } #ifdef MAC /* Wrapper to set the appropriate directory */ int get_char(generate) int *generate; { int rc, exit_flag; int16 vrefnum; (void) getsavedefaults(savefile, &vrefnum); changedirectory(vrefnum); rc = _get_char(generate, &exit_flag); restoredirectory(); if (exit_flag) exit_game(); return(rc); } #endif /* Certain checks are ommitted for the wizard. -CJS- */ #ifdef MAC int _get_char(generate, exit_flag) int *generate, *exit_flag; #else int get_char(generate) int *generate; #endif { register int i, j; int fd, c, ok, total_count; int32u l, age, time_saved; vtype temp; int16u int16u_tmp; register cave_type *c_ptr; register recall_type *r_ptr; struct misc *m_ptr; struct stats *s_ptr; register struct flags *f_ptr; store_type *st_ptr; int8u char_tmp, ychar, xchar, count; int8u version_maj, version_min, patch_level; #if defined(MSDOS) || defined(ATARI_ST) inven_type *t_ptr; #endif #ifdef MAC *exit_flag = FALSE; #endif nosignals(); *generate = TRUE; fd = -1; #ifndef MAC /* Not required for Mac, because the file name is obtained through a dialog. There is no way for a non existnat file to be specified. -BS- */ if (access(savefile, 0) != 0) { signals(); msg_print("Savefile does not exist."); return FALSE; /* Don't bother with messages here. File absent. */ } #endif clear_screen(); (void) sprintf(temp, "Savefile %s present. Attempting restore.", savefile); put_buffer(temp, 23, 0); if (turn >= 0) msg_print("IMPOSSIBLE! Attempt to restore while still alive!"); /* Allow restoring a file belonging to someone else, if we can delete it. */ /* Hence first try to read without doing a chmod. */ #if defined(MAC) || defined(AMIGA) else if ((fd = open(savefile, O_RDONLY)) < 0) #else #ifdef ATARI_ST else if (FALSE) #else else if ((fd = open(savefile, O_RDONLY, 0)) < 0 && (chmod(savefile, 0400) < 0 || (fd = open(savefile, O_RDONLY, 0)) < 0)) #endif #endif msg_print("Can't open file for reading."); else { turn = -1; ok = TRUE; (void) close(fd); fd = -1; /* Make sure it isn't closed again */ /* GCC for atari st defines atarist */ #if defined(atarist) || defined(ATARI_ST) || defined(THINK_C) || defined(MSDOS) fileptr = fopen(savefile, "rb"); #else fileptr = fopen(savefile, "r"); #endif if (fileptr == NULL) goto error; #ifdef MAC macbeginwait (); #endif prt("Restoring Memory...", 0, 0); put_qio(); DEBUG(logfile = fopen("IO_LOG", "a")); DEBUG(fprintf (logfile, "Reading data from %s\n", savefile)); xor_byte = 0; rd_byte(&version_maj); xor_byte = 0; rd_byte(&version_min); xor_byte = 0; rd_byte(&patch_level); xor_byte = 0; rd_byte(&xor_byte); /* COMPAT support savefiles from 5.0.14 to 5.0.17 */ /* support savefiles from 5.1.0 to present */ if ((version_maj != CUR_VERSION_MAJ) #if 0 /* As of version 5.4, accept savefiles even if they have higher version numbers. The savefile format was frozen as of version 5.2.2. */ || (version_min > CUR_VERSION_MIN) || (version_min == CUR_VERSION_MIN && patch_level > PATCH_LEVEL) #endif || (version_min == 0 && patch_level < 14)) { prt("Sorry. This savefile is from a different version of umoria.", 2, 0); goto error; } rd_short(&int16u_tmp); while (int16u_tmp != 0xFFFF) { if (int16u_tmp >= MAX_CREATURES) goto error; r_ptr = &c_recall[int16u_tmp]; rd_long(&r_ptr->r_cmove); rd_long(&r_ptr->r_spells); rd_short(&r_ptr->r_kills); rd_short(&r_ptr->r_deaths); rd_short(&r_ptr->r_cdefense); rd_byte(&r_ptr->r_wake); rd_byte(&r_ptr->r_ignore); rd_bytes(r_ptr->r_attacks, MAX_MON_NATTACK); rd_short(&int16u_tmp); } /* for save files before 5.2.2, read and ignore log_index (sic) */ if ((version_min < 2) || (version_min == 2 && patch_level < 2)) rd_short(&int16u_tmp); rd_long(&l); if (l & 0x1) find_cut = TRUE; else find_cut = FALSE; if (l & 0x2) find_examine = TRUE; else find_examine = FALSE; if (l & 0x4) find_prself = TRUE; else find_prself = FALSE; if (l & 0x8) find_bound = TRUE; else find_bound = FALSE; if (l & 0x10) prompt_carry_flag = TRUE; else prompt_carry_flag = FALSE; if (l & 0x20) rogue_like_commands = TRUE; else rogue_like_commands = FALSE; if (l & 0x40) show_weight_flag = TRUE; else show_weight_flag = FALSE; if (l & 0x80) highlight_seams = TRUE; else highlight_seams = FALSE; if (l & 0x100) find_ignore_doors = TRUE; else find_ignore_doors = FALSE; /* save files before 5.2.2 don't have sound_beep_flag, set it on for compatibility */ if ((version_min < 2) || (version_min == 2 && patch_level < 2)) sound_beep_flag = TRUE; else if (l & 0x200) sound_beep_flag = TRUE; else sound_beep_flag = FALSE; /* save files before 5.2.2 don't have display_counts, set it on for compatibility */ if ((version_min < 2) || (version_min == 2 && patch_level < 2)) display_counts = TRUE; else if (l & 0x400) display_counts = TRUE; else display_counts = FALSE; /* Don't allow resurrection of total_winner characters. It causes problems because the character level is out of the allowed range. */ if (to_be_wizard && (l & 0x40000000L)) { msg_print ("Sorry, this character is retired from moria."); msg_print ("You can not resurrect a retired character."); } else if (to_be_wizard && (l & 0x80000000L) && get_check("Resurrect a dead character?")) l &= ~0x80000000L; if ((l & 0x80000000L) == 0) { m_ptr = &py.misc; rd_string(m_ptr->name); rd_byte(&m_ptr->male); rd_long((int32u *)&m_ptr->au); rd_long((int32u *)&m_ptr->max_exp); rd_long((int32u *)&m_ptr->exp); rd_short(&m_ptr->exp_frac); rd_short(&m_ptr->age); rd_short(&m_ptr->ht); rd_short(&m_ptr->wt); rd_short(&m_ptr->lev); rd_short(&m_ptr->max_dlv); rd_short((int16u *)&m_ptr->srh); rd_short((int16u *)&m_ptr->fos); rd_short((int16u *)&m_ptr->bth); rd_short((int16u *)&m_ptr->bthb); rd_short((int16u *)&m_ptr->mana); rd_short((int16u *)&m_ptr->mhp); rd_short((int16u *)&m_ptr->ptohit); rd_short((int16u *)&m_ptr->ptodam); rd_short((int16u *)&m_ptr->pac); rd_short((int16u *)&m_ptr->ptoac); rd_short((int16u *)&m_ptr->dis_th); rd_short((int16u *)&m_ptr->dis_td); rd_short((int16u *)&m_ptr->dis_ac); rd_short((int16u *)&m_ptr->dis_tac); rd_short((int16u *)&m_ptr->disarm); rd_short((int16u *)&m_ptr->save); rd_short((int16u *)&m_ptr->sc); rd_short((int16u *)&m_ptr->stl); rd_byte(&m_ptr->pclass); rd_byte(&m_ptr->prace); rd_byte(&m_ptr->hitdie); rd_byte(&m_ptr->expfact); rd_short((int16u *)&m_ptr->cmana); rd_short(&m_ptr->cmana_frac); rd_short((int16u *)&m_ptr->chp); rd_short(&m_ptr->chp_frac); for (i = 0; i < 4; i++) rd_string (m_ptr->history[i]); s_ptr = &py.stats; rd_bytes(s_ptr->max_stat, 6); rd_bytes(s_ptr->cur_stat, 6); rd_shorts((int16u *)s_ptr->mod_stat, 6); rd_bytes(s_ptr->use_stat, 6); f_ptr = &py.flags; rd_long(&f_ptr->status); rd_short((int16u *)&f_ptr->rest); rd_short((int16u *)&f_ptr->blind); rd_short((int16u *)&f_ptr->paralysis); rd_short((int16u *)&f_ptr->confused); rd_short((int16u *)&f_ptr->food); rd_short((int16u *)&f_ptr->food_digested); rd_short((int16u *)&f_ptr->protection); rd_short((int16u *)&f_ptr->speed); rd_short((int16u *)&f_ptr->fast); rd_short((int16u *)&f_ptr->slow); rd_short((int16u *)&f_ptr->afraid); rd_short((int16u *)&f_ptr->poisoned); rd_short((int16u *)&f_ptr->image); rd_short((int16u *)&f_ptr->protevil); rd_short((int16u *)&f_ptr->invuln); rd_short((int16u *)&f_ptr->hero); rd_short((int16u *)&f_ptr->shero); rd_short((int16u *)&f_ptr->blessed); rd_short((int16u *)&f_ptr->resist_heat); rd_short((int16u *)&f_ptr->resist_cold); rd_short((int16u *)&f_ptr->detect_inv); rd_short((int16u *)&f_ptr->word_recall); rd_short((int16u *)&f_ptr->see_infra); rd_short((int16u *)&f_ptr->tim_infra); rd_byte(&f_ptr->see_inv); rd_byte(&f_ptr->teleport); rd_byte(&f_ptr->free_act); rd_byte(&f_ptr->slow_digest); rd_byte(&f_ptr->aggravate); rd_byte(&f_ptr->fire_resist); rd_byte(&f_ptr->cold_resist); rd_byte(&f_ptr->acid_resist); rd_byte(&f_ptr->regenerate); rd_byte(&f_ptr->lght_resist); rd_byte(&f_ptr->ffall); rd_byte(&f_ptr->sustain_str); rd_byte(&f_ptr->sustain_int); rd_byte(&f_ptr->sustain_wis); rd_byte(&f_ptr->sustain_con); rd_byte(&f_ptr->sustain_dex); rd_byte(&f_ptr->sustain_chr); rd_byte(&f_ptr->confuse_monster); rd_byte(&f_ptr->new_spells); rd_short((int16u *)&missile_ctr); rd_long((int32u *)&turn); rd_short((int16u *)&inven_ctr); if (inven_ctr > INVEN_WIELD) goto error; for (i = 0; i < inven_ctr; i++) rd_item(&inventory[i]); for (i = INVEN_WIELD; i < INVEN_ARRAY_SIZE; i++) rd_item(&inventory[i]); rd_short((int16u *)&inven_weight); rd_short((int16u *)&equip_ctr); rd_long(&spell_learned); rd_long(&spell_worked); rd_long(&spell_forgotten); rd_bytes(spell_order, 32); rd_bytes(object_ident, OBJECT_IDENT_SIZE); rd_long(&randes_seed); rd_long(&town_seed); rd_short((int16u *)&last_msg); for (i = 0; i < MAX_SAVE_MSG; i++) rd_string(old_msg[i]); rd_short((int16u *)&panic_save); rd_short((int16u *)&total_winner); rd_short((int16u *)&noscore); rd_shorts(player_hp, MAX_PLAYER_LEVEL); if ((version_min >= 2) || (version_min == 1 && patch_level >= 3)) for (i = 0; i < MAX_STORES; i++) { st_ptr = &store[i]; rd_long((int32u *)&st_ptr->store_open); rd_short((int16u *)&st_ptr->insult_cur); rd_byte(&st_ptr->owner); rd_byte(&st_ptr->store_ctr); rd_short(&st_ptr->good_buy); rd_short(&st_ptr->bad_buy); if (st_ptr->store_ctr > STORE_INVEN_MAX) goto error; for (j = 0; j < st_ptr->store_ctr; j++) { rd_long((int32u *)&st_ptr->store_inven[j].scost); rd_item(&st_ptr->store_inven[j].sitem); } } if ((version_min >= 2) || (version_min == 1 && patch_level >= 3)) rd_long(&time_saved); if (version_min >= 2) rd_string(died_from); if ((version_min >= 3) || (version_min == 2 && patch_level >= 2)) rd_long ((int32u *)&max_score); else max_score = 0; if ((version_min >= 3) || (version_min == 2 && patch_level >= 2)) rd_long ((int32u *)&birth_date); else #ifdef MAC birth_date = time((time_t *)0); #else birth_date = time((long *)0); #endif } if ((c = getc(fileptr)) == EOF || (l & 0x80000000L)) { if ((l & 0x80000000L) == 0) { if (!to_be_wizard || turn < 0) goto error; prt("Attempting a resurrection!", 0, 0); if (py.misc.chp < 0) { py.misc.chp = 0; py.misc.chp_frac = 0; } /* don't let him starve to death immediately */ if (py.flags.food < 0) py.flags.food = 0; /* don't let him die of poison again immediately */ if (py.flags.poisoned > 1) py.flags.poisoned = 1; dun_level = 0; /* Resurrect on the town level. */ character_generated = 1; /* set noscore to indicate a resurrection, and don't enter wizard mode */ to_be_wizard = FALSE; noscore |= 0x1; } else { /* Make sure that this message is seen, since it is a bit more interesting than the other messages. */ msg_print("Restoring Memory of a departed spirit..."); turn = -1; } put_qio(); goto closefiles; } if (ungetc(c, fileptr) == EOF) goto error; prt("Restoring Character...", 0, 0); put_qio(); /* only level specific info should follow, not present for dead characters */ rd_short((int16u *)&dun_level); rd_short((int16u *)&char_row); rd_short((int16u *)&char_col); rd_short((int16u *)&mon_tot_mult); rd_short((int16u *)&cur_height); rd_short((int16u *)&cur_width); rd_short((int16u *)&max_panel_rows); rd_short((int16u *)&max_panel_cols); /* read in the creature ptr info */ rd_byte(&char_tmp); while (char_tmp != 0xFF) { ychar = char_tmp; rd_byte(&xchar); rd_byte(&char_tmp); if (xchar > MAX_WIDTH || ychar > MAX_HEIGHT) goto error; cave[ychar][xchar].cptr = char_tmp; rd_byte(&char_tmp); } /* read in the treasure ptr info */ rd_byte(&char_tmp); while (char_tmp != 0xFF) { ychar = char_tmp; rd_byte(&xchar); rd_byte(&char_tmp); if (xchar > MAX_WIDTH || ychar > MAX_HEIGHT) goto error; cave[ychar][xchar].tptr = char_tmp; rd_byte(&char_tmp); } /* read in the rest of the cave info */ c_ptr = &cave[0][0]; total_count = 0; while (total_count != MAX_HEIGHT*MAX_WIDTH) { rd_byte(&count); rd_byte(&char_tmp); for (i = count; i > 0; i--) { #ifndef ATARIST_MWC if (c_ptr >= &cave[MAX_HEIGHT][0]) goto error; #endif c_ptr->fval = char_tmp & 0xF; c_ptr->lr = (char_tmp >> 4) & 0x1; c_ptr->fm = (char_tmp >> 5) & 0x1; c_ptr->pl = (char_tmp >> 6) & 0x1; c_ptr->tl = (char_tmp >> 7) & 0x1; c_ptr++; } total_count += count; } rd_short((int16u *)&tcptr); if (tcptr > MAX_TALLOC) goto error; for (i = MIN_TRIX; i < tcptr; i++) rd_item(&t_list[i]); rd_short((int16u *)&mfptr); if (mfptr > MAX_MALLOC) goto error; for (i = MIN_MONIX; i < mfptr; i++) rd_monster(&m_list[i]); #if defined(MSDOS) || defined(ATARI_ST) /* change walls and floors to graphic symbols */ t_ptr = &t_list[tcptr - 1]; for (i = tcptr - 1; i >= MIN_TRIX; i--) { #ifdef MSDOS if (t_ptr->tchar == '#') t_ptr->tchar = wallsym; #endif #ifdef ATARI_ST if (t_ptr->tchar == '#') t_ptr->tchar = (unsigned char) 240; #endif t_ptr--; } #endif *generate = FALSE; /* We have restored a cave - no need to generate. */ if ((version_min == 1 && patch_level < 3) || (version_min == 0)) for (i = 0; i < MAX_STORES; i++) { st_ptr = &store[i]; rd_long((int32u *)&st_ptr->store_open); rd_short((int16u *)&st_ptr->insult_cur); rd_byte(&st_ptr->owner); rd_byte(&st_ptr->store_ctr); rd_short(&st_ptr->good_buy); rd_short(&st_ptr->bad_buy); if (st_ptr->store_ctr > STORE_INVEN_MAX) goto error; for (j = 0; j < st_ptr->store_ctr; j++) { rd_long((int32u *)&st_ptr->store_inven[j].scost); rd_item(&st_ptr->store_inven[j].sitem); } } /* read the time that the file was saved */ if (version_min == 0 && patch_level < 16) time_saved = 0; /* no time in file, clear to zero */ else if (version_min == 1 && patch_level < 3) rd_long(&time_saved); if (ferror(fileptr)) goto error; if (turn < 0) error: ok = FALSE; /* Assume bad data. */ else { /* don't overwrite the killed by string if character is dead */ if (py.misc.chp >= 0) (void) strcpy(died_from, "(alive and well)"); character_generated = 1; } closefiles: DEBUG(fclose (logfile)); if (fileptr != NULL) { if (fclose(fileptr) < 0) ok = FALSE; } if (fd >= 0) (void) close(fd); #ifdef MAC macendwait (); #endif if (!ok) msg_print("Error during reading of file."); else { /* let the user overwrite the old savefile when save/quit */ from_savefile = 1; signals(); if (panic_save == 1) { (void) sprintf(temp, "This game is from a panic save. \ Score will not be added to scoreboard."); msg_print (temp); } else if ((!noscore & 0x04) && duplicate_character ()) { (void) sprintf (temp, "This character is already on the \ scoreboard; it will not be scored again."); msg_print (temp); noscore |= 0x4; } if (turn >= 0) { /* Only if a full restoration. */ weapon_heavy = FALSE; pack_heavy = 0; check_strength(); /* rotate store inventory, depending on how old the save file */ /* is foreach day old (rounded up), call store_maint */ /* calculate age in seconds */ #ifdef MAC start_time = time((time_t *)0); #else start_time = time((long *)0); #endif /* check for reasonable values of time here ... */ if (start_time < time_saved) age = 0; else age = start_time - time_saved; age = (age + 43200L) / 86400L; /* age in days */ if (age > 10) age = 10; /* in case savefile is very old */ for (i = 0; i < age; i++) store_maint(); } if (noscore) msg_print("This save file cannot be used to get on the score board."); if (version_maj != CUR_VERSION_MAJ || version_min != CUR_VERSION_MIN) { (void) sprintf(temp, "Save file version %d.%d %s on game version %d.%d.", version_maj, version_min, version_min <= CUR_VERSION_MIN ? "accepted" : "risky" , CUR_VERSION_MAJ, CUR_VERSION_MIN); msg_print(temp); } if (turn >= 0) return TRUE; else return FALSE; /* Only restored options and monster memory. */ } } turn = -1; prt("Please try again without that savefile.", 1, 0); signals(); #ifdef MAC *exit_flag = TRUE; #else exit_game(); #endif return FALSE; /* not reached, unless on mac */ } static void wr_byte(c) int8u c; { xor_byte ^= c; (void) putc((int)xor_byte, fileptr); DEBUG(fprintf (logfile, "BYTE: %02X = %d\n", (int) xor_byte, (int) c)); } static void wr_short(s) int16u s; { xor_byte ^= (s & 0xFF); (void) putc((int)xor_byte, fileptr); DEBUG(fprintf (logfile, "SHORT: %02X", (int) xor_byte)); xor_byte ^= ((s >> 8) & 0xFF); (void) putc((int)xor_byte, fileptr); DEBUG(fprintf (logfile, " %02X = %d\n", (int) xor_byte, (int) s)); } static void wr_long(l) register int32u l; { xor_byte ^= (l & 0xFF); (void) putc((int)xor_byte, fileptr); DEBUG(fprintf (logfile, "LONG: %02X", (int) xor_byte)); xor_byte ^= ((l >> 8) & 0xFF); (void) putc((int)xor_byte, fileptr); DEBUG(fprintf (logfile, " %02X", (int) xor_byte)); xor_byte ^= ((l >> 16) & 0xFF); (void) putc((int)xor_byte, fileptr); DEBUG(fprintf (logfile, " %02X", (int) xor_byte)); xor_byte ^= ((l >> 24) & 0xFF); (void) putc((int)xor_byte, fileptr); DEBUG(fprintf (logfile, " %02X = %ld\n", (int) xor_byte, (long) l)); } static void wr_bytes(c, count) int8u *c; register int count; { register int i; register int8u *ptr; DEBUG(fprintf (logfile, "%d BYTES:", count)); ptr = c; for (i = 0; i < count; i++) { xor_byte ^= *ptr++; (void) putc((int)xor_byte, fileptr); DEBUG(fprintf (logfile, " %02X = %d", (int) xor_byte, (int) (ptr[-1]))); } DEBUG(fprintf (logfile, "\n")); } static void wr_string(str) register char *str; { DEBUG(char *s = str); DEBUG(fprintf (logfile, "STRING:")); while (*str != '\0') { xor_byte ^= *str++; (void) putc((int)xor_byte, fileptr); DEBUG(fprintf (logfile, " %02X", (int) xor_byte)); } xor_byte ^= *str; (void) putc((int)xor_byte, fileptr); DEBUG(fprintf (logfile, " %02X = \"%s\"\n", (int) xor_byte, s)); } static void wr_shorts(s, count) int16u *s; register int count; { register int i; register int16u *sptr; DEBUG(fprintf (logfile, "%d SHORTS:", count)); sptr = s; for (i = 0; i < count; i++) { xor_byte ^= (*sptr & 0xFF); (void) putc((int)xor_byte, fileptr); DEBUG(fprintf (logfile, " %02X", (int) xor_byte)); xor_byte ^= ((*sptr++ >> 8) & 0xFF); (void) putc((int)xor_byte, fileptr); DEBUG(fprintf (logfile, " %02X = %d", (int) xor_byte, (int) sptr[-1])); } DEBUG(fprintf (logfile, "\n")); } static void wr_item(item) register inven_type *item; { DEBUG(fprintf (logfile, "ITEM:\n")); wr_short(item->index); wr_byte(item->name2); wr_string(item->inscrip); wr_long(item->flags); wr_byte(item->tval); wr_byte(item->tchar); wr_short((int16u)item->p1); wr_long((int32u)item->cost); wr_byte(item->subval); wr_byte(item->number); wr_short(item->weight); wr_short((int16u)item->tohit); wr_short((int16u)item->todam); wr_short((int16u)item->ac); wr_short((int16u)item->toac); wr_bytes(item->damage, 2); wr_byte(item->level); wr_byte(item->ident); } static void wr_monster(mon) register monster_type *mon; { DEBUG(fprintf (logfile, "MONSTER:\n")); wr_short((int16u)mon->hp); wr_short((int16u)mon->csleep); wr_short((int16u)mon->cspeed); wr_short(mon->mptr); wr_byte(mon->fy); wr_byte(mon->fx); wr_byte(mon->cdis); wr_byte(mon->ml); wr_byte(mon->stunned); wr_byte(mon->confused); } static void rd_byte(ptr) int8u *ptr; { int8u c; c = getc(fileptr) & 0xFF; *ptr = c ^ xor_byte; xor_byte = c; DEBUG(fprintf (logfile, "BYTE: %02X = %d\n", (int) c, (int) *ptr)); } static void rd_short(ptr) int16u *ptr; { int8u c; int16u s; c = (getc(fileptr) & 0xFF); s = c ^ xor_byte; xor_byte = (getc(fileptr) & 0xFF); s |= (int16u)(c ^ xor_byte) << 8; *ptr = s; DEBUG(fprintf (logfile, "SHORT: %02X %02X = %d\n", (int) c, (int) xor_byte,\ (int) s)); } static void rd_long(ptr) int32u *ptr; { register int32u l; register int8u c; c = (getc(fileptr) & 0xFF); l = c ^ xor_byte; xor_byte = (getc(fileptr) & 0xFF); l |= (int32u)(c ^ xor_byte) << 8; DEBUG(fprintf (logfile, "LONG: %02X %02X ", (int) c, (int) xor_byte)); c = (getc(fileptr) & 0xFF); l |= (int32u)(c ^ xor_byte) << 16; xor_byte = (getc(fileptr) & 0xFF); l |= (int32u)(c ^ xor_byte) << 24; *ptr = l; DEBUG(fprintf (logfile, "%02X %02X = %ld\n", (int) c, (int) xor_byte,\ (long) l)); } static void rd_bytes(ch_ptr, count) int8u *ch_ptr; register int count; { register int i; register int8u *ptr; register int8u c; DEBUG(fprintf (logfile, "%d BYTES:", count)); ptr = ch_ptr; for (i = 0; i < count; i++) { c = (getc(fileptr) & 0xFF); *ptr++ = c ^ xor_byte; xor_byte = c; DEBUG(fprintf (logfile, " %02X = %d", (int) c, (int) ptr[-1])); } DEBUG(fprintf (logfile, "\n")); } static void rd_string(str) char *str; { register int8u c; DEBUG(char *s = str); DEBUG(fprintf (logfile, "STRING: ")); do { c = (getc(fileptr) & 0xFF); *str = c ^ xor_byte; xor_byte = c; DEBUG(fprintf (logfile, "%02X ", (int) c)); } while (*str++ != '\0'); DEBUG(fprintf (logfile, "= \"%s\"\n", s)); } static void rd_shorts(ptr, count) int16u *ptr; register int count; { register int i; register int16u *sptr; register int16u s; int8u c; DEBUG(fprintf (logfile, "%d SHORTS:", count)); sptr = ptr; for (i = 0; i < count; i++) { c = (getc(fileptr) & 0xFF); s = c ^ xor_byte; xor_byte = (getc(fileptr) & 0xFF); s |= (int16u)(c ^ xor_byte) << 8; *sptr++ = s; DEBUG(fprintf (logfile, " %02X %02X = %d", (int) c, (int) xor_byte,\ (int) s)); } DEBUG(fprintf (logfile, "\n")); } static void rd_item(item) register inven_type *item; { DEBUG(fprintf (logfile, "ITEM:\n")); rd_short(&item->index); rd_byte(&item->name2); rd_string(item->inscrip); rd_long(&item->flags); rd_byte(&item->tval); rd_byte(&item->tchar); rd_short((int16u *)&item->p1); rd_long((int32u *)&item->cost); rd_byte(&item->subval); rd_byte(&item->number); rd_short(&item->weight); rd_short((int16u *)&item->tohit); rd_short((int16u *)&item->todam); rd_short((int16u *)&item->ac); rd_short((int16u *)&item->toac); rd_bytes(item->damage, 2); rd_byte(&item->level); rd_byte(&item->ident); } static void rd_monster(mon) register monster_type *mon; { DEBUG(fprintf (logfile, "MONSTER:\n")); rd_short((int16u *)&mon->hp); rd_short((int16u *)&mon->csleep); rd_short((int16u *)&mon->cspeed); rd_short(&mon->mptr); rd_byte(&mon->fy); rd_byte(&mon->fx); rd_byte(&mon->cdis); rd_byte(&mon->ml); rd_byte(&mon->stunned); rd_byte(&mon->confused); } /* functions called from death.c to implement the score file */ /* set the local fileptr to the scorefile fileptr */ void set_fileptr(file) FILE *file; { fileptr = file; } void wr_highscore(score) high_scores *score; { DEBUG(logfile = fopen ("IO_LOG", "a")); DEBUG(fprintf (logfile, "Saving score:\n")); /* Save the encryption byte for robustness. */ wr_byte(xor_byte); wr_long((int32u) score->points); wr_long((int32u) score->birth_date); wr_short((int16u) score->uid); wr_short((int16u) score->mhp); wr_short((int16u) score->chp); wr_byte(score->dun_level); wr_byte(score->lev); wr_byte(score->max_dlv); wr_byte(score->sex); wr_byte(score->race); wr_byte(score->class); wr_bytes((int8u *)score->name, PLAYER_NAME_SIZE); wr_bytes((int8u *)score->died_from, 25); DEBUG(fclose (logfile)); } void rd_highscore(score) high_scores *score; { DEBUG(logfile = fopen ("IO_LOG", "a")); DEBUG(fprintf (logfile, "Reading score:\n")); /* Read the encryption byte. */ rd_byte (&xor_byte); rd_long((int32u *)&score->points); rd_long((int32u *)&score->birth_date); rd_short((int16u *)&score->uid); rd_short((int16u *)&score->mhp); rd_short((int16u *)&score->chp); rd_byte(&score->dun_level); rd_byte(&score->lev); rd_byte(&score->max_dlv); rd_byte(&score->sex); rd_byte(&score->race); rd_byte(&score->class); rd_bytes((int8u *)score->name, PLAYER_NAME_SIZE); rd_bytes((int8u *)score->died_from, 25); DEBUG(fclose (logfile)); } moria-5.6.debian.1/source/rnd.c0000644000175000017500000000715211074756544014434 0ustar pjbpjb/* source/rnd.c: random number generator Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include "config.h" #include "constant.h" #include "types.h" /* Define this to compile as a standalone test */ /* #define TEST_RNG */ /* This alg uses a prime modulus multiplicative congruential generator (PMMLCG), also known as a Lehmer Grammer, which satisfies the following properties (i) modulus: m - a large prime integer (ii) multiplier: a - an integer in the range 2, 3, ..., m - 1 (iii) z[n+1] = f(z[n]), for n = 1, 2, ... (iv) f(z) = az mod m (v) u[n] = z[n] / m, for n = 1, 2, ... The sequence of z's must be initialized by choosing an initial seed z[1] from the range 1, 2, ..., m - 1. The sequence of z's is a pseudo- random sequence drawn without replacement from the set 1, 2, ..., m - 1. The u's form a psuedo-random sequence of real numbers between (but not including) 0 and 1. Schrage's method is used to compute the sequence of z's. Let m = aq + r, where q = m div a, and r = m mod a. Then f(z) = az mod m = az - m * (az div m) = = gamma(z) + m * delta(z) Where gamma(z) = a(z mod q) - r(z div q) and delta(z) = (z div q) - (az div m) If r < q, then for all z in 1, 2, ..., m - 1: (1) delta(z) is either 0 or 1 (2) both a(z mod q) and r(z div q) are in 0, 1, ..., m - 1 (3) absolute value of gamma(z) <= m - 1 (4) delta(z) = 1 iff gamma(z) < 0 Hence each value of z can be computed exactly without overflow as long as m can be represented as an integer. */ /* a good random number generator, correct on any machine with 32 bit integers, this algorithm is from: Stephen K. Park and Keith W. Miller, "Random Number Generators: Good ones are hard to find", Communications of the ACM, October 1988, vol 31, number 10, pp. 1192-1201. If this algorithm is implemented correctly, then if z[1] = 1, then z[10001] will equal 1043618065 Has a full period of 2^31 - 1. Returns integers in the range 1 to 2^31-1. */ #define RNG_M 2147483647L /* m = 2^31 - 1 */ #define RNG_A 16807L #define RNG_Q 127773L /* m div a */ #define RNG_R 2836L /* m mod a */ /* 32 bit seed */ static int32u rnd_seed; int32u get_rnd_seed () { return rnd_seed; } void set_rnd_seed (seedval) int32u seedval; { /* set seed to value between 1 and m-1 */ rnd_seed = (seedval % (RNG_M - 1)) + 1; } /* returns a pseudo-random number from set 1, 2, ..., RNG_M - 1 */ int32 rnd () { register long low, high, test; high = rnd_seed / RNG_Q; low = rnd_seed % RNG_Q; test = RNG_A * low - RNG_R * high; if (test > 0) rnd_seed = test; else rnd_seed = test + RNG_M; return rnd_seed; } #ifdef TEST_RNG main () { long i, random; set_rnd_seed (0L); for (i = 1; i < 10000; i++) (void) rnd (); random = rnd (); printf ("z[10001] = %ld, should be 1043618065\n", random); if (random == 1043618065L) printf ("success!!!\n"); } #endif moria-5.6.debian.1/source/misc2.c0000644000175000017500000006516011074756544014671 0ustar pjbpjb/* source/misc2.c: misc utility and initialization code, magic objects code Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" /* Chance of treasure having magic abilities -RAK- */ /* Chance increases with each dungeon level */ void magic_treasure(x, level) int x, level; { register inven_type *t_ptr; register int chance, special, cursed, i; int tmp; #ifdef ATARIST_MWC int32u holder; #endif chance = OBJ_BASE_MAGIC + level; if (chance > OBJ_BASE_MAX) chance = OBJ_BASE_MAX; special = chance / OBJ_DIV_SPECIAL; cursed = (10 * chance) / OBJ_DIV_CURSED; t_ptr = &t_list[x]; /* some objects appear multiple times in the object_list with different levels, this is to make the object occur more often, however, for consistency, must set the level of these duplicates to be the same as the object with the lowest level */ /* Depending on treasure type, it can have certain magical properties*/ switch (t_ptr->tval) { case TV_SHIELD: case TV_HARD_ARMOR: case TV_SOFT_ARMOR: if (magik(chance)) { t_ptr->toac += m_bonus(1, 30, level); if (magik(special)) switch(randint(9)) { case 1: #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_RES_LIGHT|TR_RES_COLD|TR_RES_ACID| TR_RES_FIRE); #else t_ptr->flags |= (TR_RES_LIGHT|TR_RES_COLD|TR_RES_ACID| TR_RES_FIRE); #endif t_ptr->name2 = SN_R; t_ptr->toac += 5; t_ptr->cost += 2500; break; case 2: /* Resist Acid */ #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_RES_ACID); #else t_ptr->flags |= TR_RES_ACID; #endif t_ptr->name2 = SN_RA; t_ptr->cost += 1000; break; case 3: case 4: /* Resist Fire */ #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_RES_FIRE); #else t_ptr->flags |= TR_RES_FIRE; #endif t_ptr->name2 = SN_RF; t_ptr->cost += 600; break; case 5: case 6: /* Resist Cold */ #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_RES_COLD); #else t_ptr->flags |= TR_RES_COLD; #endif t_ptr->name2 = SN_RC; t_ptr->cost += 600; break; case 7: case 8: case 9: /* Resist Lightning*/ #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_RES_LIGHT); #else t_ptr->flags |= TR_RES_LIGHT; #endif t_ptr->name2 = SN_RL; t_ptr->cost += 500; break; } } else if (magik(cursed)) { t_ptr->toac -= m_bonus(1, 40, level); t_ptr->cost = 0; #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_CURSED); #else t_ptr->flags |= TR_CURSED; #endif } break; case TV_HAFTED: case TV_POLEARM: case TV_SWORD: /* always show tohit/todam values if identified */ t_ptr->ident |= ID_SHOW_HITDAM; if (magik(chance)) { t_ptr->tohit += m_bonus(0, 40, level); /* Magical damage bonus now proportional to weapon base damage */ tmp = t_ptr->damage[0] * t_ptr->damage[1]; t_ptr->todam += m_bonus(0, 4*tmp, tmp*level/10); /* the 3*special/2 is needed because weapons are not as common as before change to treasure distribution, this helps keep same number of ego weapons same as before, see also missiles */ if (magik(3*special/2)) switch(randint(16)) { case 1: /* Holy Avenger */ #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_SEE_INVIS|TR_SUST_STAT| TR_SLAY_UNDEAD|TR_SLAY_EVIL|TR_STR); #else t_ptr->flags |= (TR_SEE_INVIS|TR_SUST_STAT|TR_SLAY_UNDEAD| TR_SLAY_EVIL|TR_STR); #endif t_ptr->tohit += 5; t_ptr->todam += 5; t_ptr->toac += randint(4); /* the value in p1 is used for strength increase */ /* p1 is also used for sustain stat */ t_ptr->p1 = randint(4); t_ptr->name2 = SN_HA; t_ptr->cost += t_ptr->p1*500; t_ptr->cost += 10000; break; case 2: /* Defender */ #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_FFALL|TR_RES_LIGHT|TR_SEE_INVIS| TR_FREE_ACT|TR_RES_COLD|TR_RES_ACID| TR_RES_FIRE|TR_REGEN|TR_STEALTH); #else t_ptr->flags |= (TR_FFALL|TR_RES_LIGHT|TR_SEE_INVIS|TR_FREE_ACT |TR_RES_COLD|TR_RES_ACID|TR_RES_FIRE| TR_REGEN|TR_STEALTH); #endif t_ptr->tohit += 3; t_ptr->todam += 3; t_ptr->toac += 5 + randint(5); t_ptr->name2 = SN_DF; /* the value in p1 is used for stealth */ t_ptr->p1 = randint(3); t_ptr->cost += t_ptr->p1*500; t_ptr->cost += 7500; break; case 3: case 4: /* Slay Animal */ t_ptr->flags |= TR_SLAY_ANIMAL; t_ptr->tohit += 2; t_ptr->todam += 2; t_ptr->name2 = SN_SA; t_ptr->cost += 3000; break; case 5: case 6: /* Slay Dragon */ t_ptr->flags |= TR_SLAY_DRAGON; t_ptr->tohit += 3; t_ptr->todam += 3; t_ptr->name2 = SN_SD; t_ptr->cost += 4000; break; case 7: case 8: /* Slay Evil */ t_ptr->flags |= TR_SLAY_EVIL; t_ptr->tohit += 3; t_ptr->todam += 3; t_ptr->name2 = SN_SE; t_ptr->cost += 4000; break; case 9: case 10: /* Slay Undead */ #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_SEE_INVIS|TR_SLAY_UNDEAD); #else t_ptr->flags |= (TR_SEE_INVIS|TR_SLAY_UNDEAD); #endif t_ptr->tohit += 3; t_ptr->todam += 3; t_ptr->name2 = SN_SU; t_ptr->cost += 5000; break; case 11: case 12: case 13: /* Flame Tongue */ #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_FLAME_TONGUE); #else t_ptr->flags |= TR_FLAME_TONGUE; #endif t_ptr->tohit++; t_ptr->todam += 3; t_ptr->name2 = SN_FT; t_ptr->cost += 2000; break; case 14: case 15: case 16: /* Frost Brand */ #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_FROST_BRAND); #else t_ptr->flags |= TR_FROST_BRAND; #endif t_ptr->tohit++; t_ptr->todam++; t_ptr->name2 = SN_FB; t_ptr->cost += 1200; break; } } else if (magik(cursed)) { t_ptr->tohit -= m_bonus(1, 55, level); /* Magical damage bonus now proportional to weapon base damage */ tmp = t_ptr->damage[0] * t_ptr->damage[1]; t_ptr->todam -= m_bonus(1, 11*tmp/2, tmp*level/10); #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_CURSED); #else t_ptr->flags |= TR_CURSED; #endif t_ptr->cost = 0; } break; case TV_BOW: /* always show tohit/todam values if identified */ t_ptr->ident |= ID_SHOW_HITDAM; if (magik(chance)) { t_ptr->tohit += m_bonus(1, 30, level); t_ptr->todam += m_bonus(1, 20, level); /* add damage. -CJS- */ } else if (magik(cursed)) { t_ptr->tohit -= m_bonus(1, 50, level); t_ptr->todam -= m_bonus(1, 30, level); /* add damage. -CJS- */ #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_CURSED); #else t_ptr->flags |= TR_CURSED; #endif t_ptr->cost = 0; } break; case TV_DIGGING: /* always show tohit/todam values if identified */ t_ptr->ident |= ID_SHOW_HITDAM; if (magik(chance)) { tmp = randint(3); if (tmp < 3) t_ptr->p1 += m_bonus(0, 25, level); else { /* a cursed digging tool */ t_ptr->p1 = -m_bonus(1, 30, level); t_ptr->cost = 0; #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_CURSED); #else t_ptr->flags |= TR_CURSED; #endif } } break; case TV_GLOVES: if (magik(chance)) { t_ptr->toac += m_bonus(1, 20, level); if (magik(special)) { if (randint(2) == 1) { #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_FREE_ACT); #else t_ptr->flags |= TR_FREE_ACT; #endif t_ptr->name2 = SN_FREE_ACTION; t_ptr->cost += 1000; } else { t_ptr->ident |= ID_SHOW_HITDAM; t_ptr->tohit += 1 + randint(3); t_ptr->todam += 1 + randint(3); t_ptr->name2 = SN_SLAYING; t_ptr->cost += (t_ptr->tohit+t_ptr->todam)*250; } } } else if (magik(cursed)) { if (magik(special)) { if (randint(2) == 1) { t_ptr->flags |= TR_DEX; t_ptr->name2 = SN_CLUMSINESS; } else { t_ptr->flags |= TR_STR; t_ptr->name2 = SN_WEAKNESS; } t_ptr->ident |= ID_SHOW_P1; t_ptr->p1 = -m_bonus(1, 10, level); } t_ptr->toac -= m_bonus(1, 40, level); #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_CURSED); #else t_ptr->flags |= TR_CURSED; #endif t_ptr->cost = 0; } break; case TV_BOOTS: if (magik(chance)) { t_ptr->toac += m_bonus(1, 20, level); if (magik(special)) { tmp = randint(12); if (tmp > 5) { #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_FFALL); #else t_ptr->flags |= TR_FFALL; #endif t_ptr->name2 = SN_SLOW_DESCENT; t_ptr->cost += 250; } else if (tmp == 1) { t_ptr->flags |= TR_SPEED; t_ptr->name2 = SN_SPEED; t_ptr->ident |= ID_SHOW_P1; t_ptr->p1 = 1; t_ptr->cost += 5000; } else /* 2 - 5 */ { t_ptr->flags |= TR_STEALTH; t_ptr->ident |= ID_SHOW_P1; t_ptr->p1 = randint(3); t_ptr->name2 = SN_STEALTH; t_ptr->cost += 500; } } } else if (magik(cursed)) { tmp = randint(3); if (tmp == 1) { t_ptr->flags |= TR_SPEED; t_ptr->name2 = SN_SLOWNESS; t_ptr->ident |= ID_SHOW_P1; t_ptr->p1 = -1; } else if (tmp == 2) { t_ptr->flags |= TR_AGGRAVATE; t_ptr->name2 = SN_NOISE; } else { t_ptr->name2 = SN_GREAT_MASS; t_ptr->weight = t_ptr->weight * 5; } t_ptr->cost = 0; t_ptr->toac -= m_bonus(2, 45, level); #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_CURSED); #else t_ptr->flags |= TR_CURSED; #endif } break; case TV_HELM: /* Helms */ if ((t_ptr->subval >= 6) && (t_ptr->subval <= 8)) { /* give crowns a higher chance for magic */ chance += (int) (t_ptr->cost / 100); special += special; } if (magik(chance)) { t_ptr->toac += m_bonus(1, 20, level); if (magik(special)) { if (t_ptr->subval < 6) { tmp = randint(3); t_ptr->ident |= ID_SHOW_P1; if (tmp == 1) { t_ptr->p1 = randint(2); t_ptr->flags |= TR_INT; t_ptr->name2 = SN_INTELLIGENCE; t_ptr->cost += t_ptr->p1*500; } else if (tmp == 2) { t_ptr->p1 = randint(2); t_ptr->flags |= TR_WIS; t_ptr->name2 = SN_WISDOM; t_ptr->cost += t_ptr->p1*500; } else { t_ptr->p1 = 1 + randint(4); #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_INFRA); #else t_ptr->flags |= TR_INFRA; #endif t_ptr->name2 = SN_INFRAVISION; t_ptr->cost += t_ptr->p1*250; } } else { switch(randint(6)) { case 1: t_ptr->ident |= ID_SHOW_P1; t_ptr->p1 = randint(3); #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_FREE_ACT|TR_CON|TR_DEX| TR_STR); #else t_ptr->flags |= (TR_FREE_ACT|TR_CON|TR_DEX|TR_STR); #endif t_ptr->name2 = SN_MIGHT; t_ptr->cost += 1000 + t_ptr->p1*500; break; case 2: t_ptr->ident |= ID_SHOW_P1; t_ptr->p1 = randint(3); t_ptr->flags |= (TR_CHR|TR_WIS); t_ptr->name2 = SN_LORDLINESS; t_ptr->cost += 1000 + t_ptr->p1*500; break; case 3: t_ptr->ident |= ID_SHOW_P1; t_ptr->p1 = randint(3); #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_RES_LIGHT|TR_RES_COLD| TR_RES_ACID|TR_RES_FIRE|TR_INT); #else t_ptr->flags |= (TR_RES_LIGHT|TR_RES_COLD|TR_RES_ACID| TR_RES_FIRE|TR_INT); #endif t_ptr->name2 = SN_MAGI; t_ptr->cost += 3000 + t_ptr->p1*500; break; case 4: t_ptr->ident |= ID_SHOW_P1; t_ptr->p1 = randint(3); t_ptr->flags |= TR_CHR; t_ptr->name2 = SN_BEAUTY; t_ptr->cost += 750; break; case 5: t_ptr->ident |= ID_SHOW_P1; t_ptr->p1 = 5*(1 + randint(4)); #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_SEE_INVIS|TR_SEARCH); #else t_ptr->flags |= (TR_SEE_INVIS|TR_SEARCH); #endif t_ptr->name2 = SN_SEEING; t_ptr->cost += 1000 + t_ptr->p1*100; break; case 6: t_ptr->flags |= TR_REGEN; t_ptr->name2 = SN_REGENERATION; t_ptr->cost += 1500; break; } } } } else if (magik(cursed)) { t_ptr->toac -= m_bonus(1, 45, level); #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_CURSED); #else t_ptr->flags |= TR_CURSED; #endif t_ptr->cost = 0; if (magik(special)) switch(randint(7)) { case 1: t_ptr->ident |= ID_SHOW_P1; t_ptr->p1 = -randint (5); t_ptr->flags |= TR_INT; t_ptr->name2 = SN_STUPIDITY; break; case 2: t_ptr->ident |= ID_SHOW_P1; t_ptr->p1 = -randint (5); t_ptr->flags |= TR_WIS; t_ptr->name2 = SN_DULLNESS; break; case 3: #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_BLIND); #else t_ptr->flags |= TR_BLIND; #endif t_ptr->name2 = SN_BLINDNESS; break; case 4: #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_TIMID); #else t_ptr->flags |= TR_TIMID; #endif t_ptr->name2 = SN_TIMIDNESS; break; case 5: t_ptr->ident |= ID_SHOW_P1; t_ptr->p1 = -randint (5); t_ptr->flags |= TR_STR; t_ptr->name2 = SN_WEAKNESS; break; case 6: t_ptr->flags |= TR_TELEPORT; t_ptr->name2 = SN_TELEPORTATION; break; case 7: t_ptr->ident |= ID_SHOW_P1; t_ptr->p1 = -randint (5); t_ptr->flags |= TR_CHR; t_ptr->name2 = SN_UGLINESS; break; } } break; case TV_RING: /* Rings */ switch(t_ptr->subval) { case 0: case 1: case 2: case 3: if (magik(cursed)) { t_ptr->p1 = -m_bonus(1, 20, level); #ifdef ATARIST_MWC t_ptr->flags |= TR_CURSED; #else t_ptr->flags |= TR_CURSED; #endif t_ptr->cost = -t_ptr->cost; } else { t_ptr->p1 = m_bonus(1, 10, level); t_ptr->cost += t_ptr->p1*100; } break; case 4: if (magik(cursed)) { t_ptr->p1 = -randint(3); #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_CURSED); #else t_ptr->flags |= TR_CURSED; #endif t_ptr->cost = -t_ptr->cost; } else t_ptr->p1 = 1; break; case 5: t_ptr->p1 = 5 * m_bonus(1, 20, level); t_ptr->cost += t_ptr->p1*50; if (magik (cursed)) { t_ptr->p1 = -t_ptr->p1; #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_CURSED); #else t_ptr->flags |= TR_CURSED; #endif t_ptr->cost = -t_ptr->cost; } break; case 19: /* Increase damage */ t_ptr->todam += m_bonus(1, 20, level); t_ptr->cost += t_ptr->todam*100; if (magik(cursed)) { t_ptr->todam = -t_ptr->todam; #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_CURSED); #else t_ptr->flags |= TR_CURSED; #endif t_ptr->cost = -t_ptr->cost; } break; case 20: /* Increase To-Hit */ t_ptr->tohit += m_bonus(1, 20, level); t_ptr->cost += t_ptr->tohit*100; if (magik(cursed)) { t_ptr->tohit = -t_ptr->tohit; #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_CURSED); #else t_ptr->flags |= TR_CURSED; #endif t_ptr->cost = -t_ptr->cost; } break; case 21: /* Protection */ t_ptr->toac += m_bonus(1, 20, level); t_ptr->cost += t_ptr->toac*100; if (magik(cursed)) { t_ptr->toac = -t_ptr->toac; #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_CURSED); #else t_ptr->flags |= TR_CURSED; #endif t_ptr->cost = -t_ptr->cost; } break; case 24: case 25: case 26: case 27: case 28: case 29: t_ptr->ident |= ID_NOSHOW_P1; break; case 30: /* Slaying */ t_ptr->ident |= ID_SHOW_HITDAM; t_ptr->todam += m_bonus(1, 25, level); t_ptr->tohit += m_bonus(1, 25, level); t_ptr->cost += (t_ptr->tohit+t_ptr->todam)*100; if (magik(cursed)) { t_ptr->tohit = -t_ptr->tohit; t_ptr->todam = -t_ptr->todam; #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_CURSED); #else t_ptr->flags |= TR_CURSED; #endif t_ptr->cost = -t_ptr->cost; } break; default: break; } break; case TV_AMULET: /* Amulets */ if (t_ptr->subval < 2) { if (magik(cursed)) { t_ptr->p1 = -m_bonus(1, 20, level); #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_CURSED); #else t_ptr->flags |= TR_CURSED; #endif t_ptr->cost = -t_ptr->cost; } else { t_ptr->p1 = m_bonus(1, 10, level); t_ptr->cost += t_ptr->p1*100; } } else if (t_ptr->subval == 2) { t_ptr->p1 = 5 * m_bonus(1, 25, level); if (magik(cursed)) { t_ptr->p1 = -t_ptr->p1; t_ptr->cost = -t_ptr->cost; #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_CURSED); #else t_ptr->flags |= TR_CURSED; #endif } else t_ptr->cost += 50*t_ptr->p1; } else if (t_ptr->subval == 8) { /* amulet of the magi is never cursed */ t_ptr->p1 = 5 * m_bonus(1, 25, level); t_ptr->cost += 20*t_ptr->p1; } break; /* Subval should be even for store, odd for dungeon*/ /* Dungeon found ones will be partially charged */ case TV_LIGHT: if ((t_ptr->subval % 2) == 1) { t_ptr->p1 = randint(t_ptr->p1); t_ptr->subval -= 1; } break; case TV_WAND: switch(t_ptr->subval) { case 0: t_ptr->p1 = randint(10) + 6; break; case 1: t_ptr->p1 = randint(8) + 6; break; case 2: t_ptr->p1 = randint(5) + 6; break; case 3: t_ptr->p1 = randint(8) + 6; break; case 4: t_ptr->p1 = randint(4) + 3; break; case 5: t_ptr->p1 = randint(8) + 6; break; case 6: t_ptr->p1 = randint(20) + 12; break; case 7: t_ptr->p1 = randint(20) + 12; break; case 8: t_ptr->p1 = randint(10) + 6; break; case 9: t_ptr->p1 = randint(12) + 6; break; case 10: t_ptr->p1 = randint(10) + 12; break; case 11: t_ptr->p1 = randint(3) + 3; break; case 12: t_ptr->p1 = randint(8) + 6; break; case 13: t_ptr->p1 = randint(10) + 6; break; case 14: t_ptr->p1 = randint(5) + 3; break; case 15: t_ptr->p1 = randint(5) + 3; break; case 16: t_ptr->p1 = randint(5) + 6; break; case 17: t_ptr->p1 = randint(5) + 4; break; case 18: t_ptr->p1 = randint(8) + 4; break; case 19: t_ptr->p1 = randint(6) + 2; break; case 20: t_ptr->p1 = randint(4) + 2; break; case 21: t_ptr->p1 = randint(8) + 6; break; case 22: t_ptr->p1 = randint(5) + 2; break; case 23: t_ptr->p1 = randint(12) + 12; break; default: break; } break; case TV_STAFF: switch(t_ptr->subval) { case 0: t_ptr->p1 = randint(20) + 12; break; case 1: t_ptr->p1 = randint(8) + 6; break; case 2: t_ptr->p1 = randint(5) + 6; break; case 3: t_ptr->p1 = randint(20) + 12; break; case 4: t_ptr->p1 = randint(15) + 6; break; case 5: t_ptr->p1 = randint(4) + 5; break; case 6: t_ptr->p1 = randint(5) + 3; break; case 7: t_ptr->p1 = randint(3) + 1; t_ptr->level = 10; break; case 8: t_ptr->p1 = randint(3) + 1; break; case 9: t_ptr->p1 = randint(5) + 6; break; case 10: t_ptr->p1 = randint(10) + 12; break; case 11: t_ptr->p1 = randint(5) + 6; break; case 12: t_ptr->p1 = randint(5) + 6; break; case 13: t_ptr->p1 = randint(5) + 6; break; case 14: t_ptr->p1 = randint(10) + 12; break; case 15: t_ptr->p1 = randint(3) + 4; break; case 16: t_ptr->p1 = randint(5) + 6; break; case 17: t_ptr->p1 = randint(5) + 6; break; case 18: t_ptr->p1 = randint(3) + 4; break; case 19: t_ptr->p1 = randint(10) + 12; break; case 20: t_ptr->p1 = randint(3) + 4; break; case 21: t_ptr->p1 = randint(3) + 4; break; case 22: t_ptr->p1 = randint(10) + 6; t_ptr->level = 5; break; default: break; } break; case TV_CLOAK: if (magik(chance)) { if (magik(special)) { if (randint(2) == 1) { t_ptr->name2 = SN_PROTECTION; t_ptr->toac += m_bonus(2, 40, level); t_ptr->cost += 250; } else { t_ptr->toac += m_bonus(1, 20, level); t_ptr->ident |= ID_SHOW_P1; t_ptr->p1 = randint(3); t_ptr->flags |= TR_STEALTH; t_ptr->name2 = SN_STEALTH; t_ptr->cost += 500; } } else t_ptr->toac += m_bonus(1, 20, level); } else if (magik(cursed)) { tmp = randint(3); if (tmp == 1) { t_ptr->flags |= TR_AGGRAVATE; t_ptr->name2 = SN_IRRITATION; t_ptr->toac -= m_bonus(1, 10, level); t_ptr->ident |= ID_SHOW_HITDAM; t_ptr->tohit -= m_bonus(1, 10, level); t_ptr->todam -= m_bonus(1, 10, level); t_ptr->cost = 0; } else if (tmp == 2) { t_ptr->name2 = SN_VULNERABILITY; t_ptr->toac -= m_bonus(10, 100, level+50); t_ptr->cost = 0; } else { t_ptr->name2 = SN_ENVELOPING; t_ptr->toac -= m_bonus(1, 10, level); t_ptr->ident |= ID_SHOW_HITDAM; t_ptr->tohit -= m_bonus(2, 40, level+10); t_ptr->todam -= m_bonus(2, 40, level+10); t_ptr->cost = 0; } #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_CURSED); #else t_ptr->flags |= TR_CURSED; #endif } break; case TV_CHEST: switch(randint(level+4)) { case 1: t_ptr->flags = 0; t_ptr->name2 = SN_EMPTY; break; case 2: t_ptr->flags |= CH_LOCKED; t_ptr->name2 = SN_LOCKED; break; case 3: case 4: t_ptr->flags |= (CH_LOSE_STR|CH_LOCKED); t_ptr->name2 = SN_POISON_NEEDLE; break; case 5: case 6: t_ptr->flags |= (CH_POISON|CH_LOCKED); t_ptr->name2 = SN_POISON_NEEDLE; break; case 7: case 8: case 9: t_ptr->flags |= (CH_PARALYSED|CH_LOCKED); t_ptr->name2 = SN_GAS_TRAP; break; case 10: case 11: t_ptr->flags |= (CH_EXPLODE|CH_LOCKED); t_ptr->name2 = SN_EXPLOSION_DEVICE; break; case 12: case 13: case 14: t_ptr->flags |= (CH_SUMMON|CH_LOCKED); t_ptr->name2 = SN_SUMMONING_RUNES; break; case 15: case 16: case 17: t_ptr->flags |= (CH_PARALYSED|CH_POISON|CH_LOSE_STR|CH_LOCKED); t_ptr->name2 = SN_MULTIPLE_TRAPS; break; default: t_ptr->flags |= (CH_SUMMON|CH_EXPLODE|CH_LOCKED); t_ptr->name2 = SN_MULTIPLE_TRAPS; break; } break; case TV_SLING_AMMO: case TV_SPIKE: case TV_BOLT: case TV_ARROW: if (t_ptr->tval == TV_SLING_AMMO || t_ptr->tval == TV_BOLT || t_ptr->tval == TV_ARROW) { /* always show tohit/todam values if identified */ t_ptr->ident |= ID_SHOW_HITDAM; if (magik(chance)) { t_ptr->tohit += m_bonus(1, 35, level); t_ptr->todam += m_bonus(1, 35, level); /* see comment for weapons */ if (magik(3*special/2)) switch(randint(10)) { case 1: case 2: case 3: t_ptr->name2 = SN_SLAYING; t_ptr->tohit += 5; t_ptr->todam += 5; t_ptr->cost += 20; break; case 4: case 5: #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_FLAME_TONGUE); #else t_ptr->flags |= TR_FLAME_TONGUE; #endif t_ptr->tohit += 2; t_ptr->todam += 4; t_ptr->name2 = SN_FIRE; t_ptr->cost += 25; break; case 6: case 7: t_ptr->flags |= TR_SLAY_EVIL; t_ptr->tohit += 3; t_ptr->todam += 3; t_ptr->name2 = SN_SLAY_EVIL; t_ptr->cost += 25; break; case 8: case 9: t_ptr->flags |= TR_SLAY_ANIMAL; t_ptr->tohit += 2; t_ptr->todam += 2; t_ptr->name2 = SN_SLAY_ANIMAL; t_ptr->cost += 30; break; case 10: t_ptr->flags |= TR_SLAY_DRAGON; t_ptr->tohit += 3; t_ptr->todam += 3; t_ptr->name2 = SN_DRAGON_SLAYING; t_ptr->cost += 35; break; } } else if (magik(cursed)) { t_ptr->tohit -= m_bonus(5, 55, level); t_ptr->todam -= m_bonus(5, 55, level); #ifdef ATARIST_MWC t_ptr->flags |= (holder = TR_CURSED); #else t_ptr->flags |= TR_CURSED; #endif t_ptr->cost = 0; } } t_ptr->number = 0; for (i = 0; i < 7; i++) t_ptr->number += randint(6); if (missile_ctr == MAX_SHORT) missile_ctr = -MAX_SHORT - 1; else missile_ctr++; t_ptr->p1 = missile_ctr; break; case TV_FOOD: /* make sure all food rations have the same level */ if (t_ptr->subval == 90) t_ptr->level = 0; /* give all elvish waybread the same level */ else if (t_ptr->subval == 92) t_ptr->level = 6; break; case TV_SCROLL1: /* give all identify scrolls the same level */ if (t_ptr->subval == 67) t_ptr->level = 1; /* scroll of light */ else if (t_ptr->subval == 69) t_ptr->level = 0; /* scroll of trap detection */ else if (t_ptr->subval == 80) t_ptr->level = 5; /* scroll of door/stair location */ else if (t_ptr->subval == 81) t_ptr->level = 5; break; case TV_POTION1: /* potions */ /* cure light */ if (t_ptr->subval == 76) t_ptr->level = 0; break; default: break; } } static struct opt_desc { char *o_prompt; int *o_var; } options[] = { { "Running: cut known corners", &find_cut }, { "Running: examine potential corners", &find_examine }, { "Running: print self during run", &find_prself }, { "Running: stop when map sector changes", &find_bound }, { "Running: run through open doors", &find_ignore_doors }, { "Prompt to pick up objects", &prompt_carry_flag }, { "Rogue like commands", &rogue_like_commands }, { "Show weights in inventory", &show_weight_flag }, { "Highlight and notice mineral seams", &highlight_seams }, { "Beep for invalid character", &sound_beep_flag }, { "Display rest/repeat counts", &display_counts }, { 0, 0 } }; /* Set or unset various boolean options. -CJS- */ void set_options() { register int i, max; vtype string; prt(" ESC when finished, y/n to set options, or - to move cursor", 0, 0); for (max = 0; options[max].o_prompt != 0; max++) { (void) sprintf(string, "%-38s: %s", options[max].o_prompt, (*options[max].o_var ? "yes" : "no ")); prt(string, max+1, 0); } erase_line(max+1, 0); i = 0; for(;;) { move_cursor(i+1, 40); switch(inkey()) { case ESCAPE: return; case '-': if (i > 0) i--; else i = max-1; break; case ' ': case '\n': case '\r': if (i+1 < max) i++; else i = 0; break; case 'y': case 'Y': put_buffer("yes", i+1, 40); *options[i].o_var = TRUE; if (i+1 < max) i++; else i = 0; break; case 'n': case 'N': put_buffer("no ", i+1, 40); *options[i].o_var = FALSE; if (i+1 < max) i++; else i = 0; break; default: bell(); break; } } } moria-5.6.debian.1/source/misc4.c0000644000175000017500000000606111074756544014666 0ustar pjbpjb/* source/misc4.c: misc code for maintaining the dungeon, printing player info Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #ifndef USG #include #include #endif #ifdef USG #ifndef ATARIST_MWC #include #endif #else #include #endif /* Add a comment to an object description. -CJS- */ void scribe_object() { int item_val, j; bigvtype out_val, tmp_str; if (inven_ctr > 0 || equip_ctr > 0) { if (get_item(&item_val, "Which one? ", 0, INVEN_ARRAY_SIZE, CNIL, CNIL)) { objdes(tmp_str, &inventory[item_val], TRUE); (void) sprintf(out_val, "Inscribing %s", tmp_str); msg_print(out_val); if (inventory[item_val].inscrip[0] != '\0') (void) sprintf(out_val, "Replace %s New inscription:", inventory[item_val].inscrip); else (void) strcpy(out_val, "Inscription: "); j = 78 - strlen(tmp_str); if (j > 12) j = 12; prt(out_val, 0, 0); if (get_string(out_val, 0, (int)strlen(out_val), j)) inscribe(&inventory[item_val], out_val); } } else msg_print("You are not carrying anything to inscribe."); } /* Append an additional comment to an object description. -CJS- */ void add_inscribe(i_ptr, type) inven_type *i_ptr; int8u type; { i_ptr->ident |= type; } /* Replace any existing comment in an object description with a new one. CJS*/ void inscribe(i_ptr, str) inven_type *i_ptr; char *str; { (void) strcpy(i_ptr->inscrip, str); } /* We need to reset the view of things. -CJS- */ void check_view() { register int i, j; register cave_type *c_ptr, *d_ptr; c_ptr = &cave[char_row][char_col]; /* Check for new panel */ if (get_panel(char_row, char_col, FALSE)) prt_map(); /* Move the light source */ move_light(char_row, char_col, char_row, char_col); /* A room of light should be lit. */ if (c_ptr->fval == LIGHT_FLOOR) { if ((py.flags.blind < 1) && !c_ptr->pl) light_room(char_row, char_col); } /* In doorway of light-room? */ else if (c_ptr->lr && (py.flags.blind < 1)) { for (i = (char_row - 1); i <= (char_row + 1); i++) for (j = (char_col - 1); j <= (char_col + 1); j++) { d_ptr = &cave[i][j]; if ((d_ptr->fval == LIGHT_FLOOR) && !d_ptr->pl) light_room(i, j); } } } moria-5.6.debian.1/source/io.c0000644000175000017500000011011611074756544014253 0ustar pjbpjb/* source/io.c: terminal I/O code, uses the curses package Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include #include "config.h" #ifdef HPUX #include #endif #if defined(atarist) && defined(__GNUC__) #include #endif #ifdef MSDOS #include #endif #ifdef AMIGA /* detach from cli process */ long _stack = 30000; long _priority = 0; long _BackGroundIO = 1; char *_procname = "Moria"; #endif #if defined(NLS) && defined(lint) /* for AIX, don't let curses include the NL stuff */ #undef NLS #endif #if !defined(GEMDOS) #ifdef MAC #ifdef THINK_C #include "ScrnMgr.h" #else #include #endif #else #include #endif #else /* GEMDOS i.e. Atari ST */ #include "curses.h" long wgetch(); #ifdef ATARIST_TC #include /* TC */ #include #else #include /* MWC */ #endif char *getenv(); #endif #include #if defined(SYS_V) && defined(lint) /* for AIX, prevent hundreds of unnecessary lint errors, must define before signal.h is included */ #define _h_IEEETRAP typedef struct { int stuff; } fpvmach; #endif #if defined(MSDOS) #if defined(ANSI) #include "ms_ansi.h" #endif #else /* not msdos */ #if !defined(ATARI_ST) && !defined(MAC) && !defined(AMIGA) #ifndef VMS #include #endif #include #endif #endif #ifndef USG /* only needed for Berkeley UNIX */ #include #include #include #endif #ifdef USG #ifndef ATARI_ST #include #else #include "string.h" #endif #if 0 /* Used to include termio.h here, but that caused problems on some systems, as curses.h includes it also above. */ #if !defined(MAC) && !defined(MSDOS) && !defined(ATARI_ST) #if !defined(AMIGA) && !defined(VMS) #include #endif #endif #endif /* 0 */ #ifdef HPUX /* Needs termio.h because curses.h doesn't include it */ #include #endif #else /* ! USG */ #include #if defined(atarist) && defined(__GNUC__) /* doesn't have sys/wait.h */ #else #include #endif #endif #include #ifdef DEBIAN_LINUX #include #endif #if defined(unix) || defined(__linux__) || defined(DEBIAN_LINUX) #include /* prototype for execl */ #endif /* These are included after other includes (particularly curses.h) to avoid redefintion warnings. */ #include "constant.h" #include "types.h" #include "externs.h" #if defined(SYS_V) && defined(lint) struct screen { int dumb; }; #endif /* Fooling lint. Unfortunately, c defines all the TIO. -CJS- constants to be long, and lint expects them to be int. Also, ioctl is sometimes called with just two arguments. The following definition keeps lint happy. It may need to be reset for different systems. */ #ifndef MAC #ifdef lint #ifdef Pyramid /* Pyramid makes constants greater than 65535 into long! Gakk! -CJS- */ /*ARGSUSED*/ /*VARARGS2*/ static Ioctl(i, l, p) long l; char *p; { return 0; } #else /*ARGSUSED*/ /*VARARGS2*/ static Ioctl(i, l, p) char *p; { return 0; } #endif #define ioctl Ioctl #endif #if !defined(USG) && defined(lint) /* This use_value hack is for curses macros which return a value, but don't shut up about it when you try to tell them (void). */ /* only needed for Berkeley UNIX */ int Use_value; #define use_value Use_value += #else #define use_value #endif #if defined(SYS_V) && defined(lint) /* This use_value2 hack is for curses macros which use a conditional expression, and which say null effect even if you cast to (void). */ /* only needed for SYS V */ int Use_value2; #define use_value2 Use_value2 += #else #define use_value2 #endif #endif #ifndef MAC char *getenv(); #endif #ifndef VMS #ifdef USG void exit(); #if defined(__TURBOC__) void sleep(); #else #ifndef AMIGA unsigned sleep(); #endif #endif #endif #endif #ifdef ultrix void exit(); void sleep(); #endif #if !defined(MAC) && !defined(MSDOS) && !defined(ATARI_ST) && !defined(VMS) #ifndef AMIGA #ifdef USG #ifdef __linux__ static struct termios save_termio; #else static struct termio save_termio; #endif #else static struct ltchars save_special_chars; static struct sgttyb save_ttyb; static struct tchars save_tchars; static int save_local_chars; #endif #endif #endif #ifndef MAC static int curses_on = FALSE; static WINDOW *savescr; /* Spare window for saving the screen. -CJS-*/ #ifdef VMS static WINDOW *tempscr; /* Spare window for VMS CTRL('R'). */ #endif #endif #ifdef MAC /* Attributes of normal and hilighted characters */ #define ATTR_NORMAL attrNormal #define ATTR_HILITED attrReversed #endif #ifndef MAC #ifdef SIGTSTP /* suspend() -CJS- Handle the stop and start signals. This ensures that the log is up to date, and that the terminal is fully reset and restored. */ int suspend() { #ifdef USG /* for USG systems with BSDisms that have SIGTSTP defined, but don't actually implement it */ #else struct sgttyb tbuf; struct ltchars lcbuf; struct tchars cbuf; int lbuf; long time(); py.misc.male |= 2; (void) ioctl(0, TIOCGETP, (char *)&tbuf); (void) ioctl(0, TIOCGETC, (char *)&cbuf); (void) ioctl(0, TIOCGLTC, (char *)&lcbuf); #if !defined(atarist) && !defined(__GNUC__) (void) ioctl(0, TIOCLGET, (char *)&lbuf); #endif restore_term(); (void) kill(0, SIGSTOP); curses_on = TRUE; (void) ioctl(0, TIOCSETP, (char *)&tbuf); (void) ioctl(0, TIOCSETC, (char *)&cbuf); (void) ioctl(0, TIOCSLTC, (char *)&lcbuf); #if !defined(atarist) && !defined(__GNUC__) (void) ioctl(0, TIOCLSET, (char *)&lbuf); #endif (void) wrefresh(curscr); py.misc.male &= ~2; #endif return 0; } #endif #endif /* initializes curses routines */ void init_curses() #ifdef MAC { /* Primary initialization is done in mac.c since game is restartable */ /* Only need to clear the screen here */ Rect scrn; scrn.left = scrn.top = 0; scrn.right = SCRN_COLS; scrn.bottom = SCRN_ROWS; EraseScreen(&scrn); UpdateScreen(); } #else { int i, y, x; #ifdef AMIGA if (opentimer() == 0) { (void) printf ("Could not open timer device.\n"); exit (1); } #endif #ifndef USG (void) ioctl(0, TIOCGLTC, (char *)&save_special_chars); (void) ioctl(0, TIOCGETP, (char *)&save_ttyb); (void) ioctl(0, TIOCGETC, (char *)&save_tchars); #if !defined(atarist) && !defined(__GNUC__) (void) ioctl(0, TIOCLGET, (char *)&save_local_chars); #endif #else #if !defined(VMS) && !defined(MSDOS) && !defined(ATARI_ST) #ifndef AMIGA (void) ioctl(0, TCGETA, (char *)&save_termio); #endif #endif #endif /* PC curses returns ERR */ #if defined(USG) && !defined(PC_CURSES) && !defined(AMIGA) if (initscr() == NULL) #else if (initscr() == ERR) #endif { (void) printf("Error allocating screen in curses package.\n"); exit(1); } if (LINES < 24 || COLS < 80) /* Check we have enough screen. -CJS- */ { (void) printf("Screen too small for moria.\n"); exit (1); } #ifdef SIGTSTP #if defined(atarist) && defined(__GNUC__) (void) signal (SIGTSTP, (__Sigfunc)suspend); #else #ifdef __386BSD__ (void) signal (SIGTSTP, (sig_t)suspend); #else #ifdef DEBIAN_LINUX /* (void) signal (SIGTSTP, (sig_t)suspend); */ /* RENMOD: libc6 defaults to BSD, this expects SYSV */ (void) sysv_signal (SIGTSTP, suspend); #else (void) signal (SIGTSTP, suspend); #endif #endif #endif #endif if (((savescr = newwin (0, 0, 0, 0)) == NULL) #ifdef VMS || ((tempscr = newwin (0, 0, 0, 0)) == NULL)) #else ) #endif { (void) printf ("Out of memory in starting up curses.\n"); exit_game(); } (void) clear(); (void) refresh(); moriaterm (); #if 0 /* This assumes that the terminal is 80 characters wide, which is not guaranteed to be true. */ /* check tab settings, exit with error if they are not 8 spaces apart */ (void) move(0, 0); for (i = 1; i < 10; i++) { (void) addch('\t'); getyx(stdscr, y, x); if (y != 0 || x != i*8) break; } if (i != 10) { msg_print("Tabs must be set 8 spaces apart."); exit_game(); } #endif } #endif /* Set up the terminal into a suitable state for moria. -CJS- */ void moriaterm() #ifdef MAC /* Nothing to do on Mac */ { } #else { #if !defined(MSDOS) && !defined(ATARI_ST) && !defined(VMS) #ifndef AMIGA #ifdef USG #ifdef __linux__ struct termios tbuf; #else struct termio tbuf; #endif #else struct ltchars lbuf; struct tchars buf; #endif #endif #endif curses_on = TRUE; #ifndef BSD4_3 use_value crmode(); #else #ifdef VMS use_value vms_crmode (); #else use_value cbreak(); #endif #endif use_value noecho(); /* can not use nonl(), because some curses do not handle it correctly */ #ifdef MSDOS msdos_raw(); #else #ifdef AMIGA init_color (0, 0, 0, 0); /* pen 0 - black */ init_color (1,1000,1000,1000); /* pen 1 - white */ init_color (2, 0, 300, 700); /* pen 2 - blue */ init_color (3,1000, 500, 0); /* pen 3 - orange */ #else #if !defined(ATARI_ST) && !defined(VMS) #ifdef USG (void) ioctl(0, TCGETA, (char *)&tbuf); /* disable all of the normal special control characters */ tbuf.c_cc[VINTR] = (char)3; /* control-C */ tbuf.c_cc[VQUIT] = (char)-1; tbuf.c_cc[VERASE] = (char)-1; tbuf.c_cc[VKILL] = (char)-1; tbuf.c_cc[VEOF] = (char)-1; /* don't know what these are for */ tbuf.c_cc[VEOL] = (char)-1; #ifdef VEOL2 tbuf.c_cc[VEOL2] = (char)-1; #endif /* stuff needed when !icanon, i.e. cbreak/raw mode */ tbuf.c_cc[VMIN] = 1; /* Input should wait for at least 1 char */ tbuf.c_cc[VTIME] = 0; /* no matter how long that takes. */ (void) ioctl(0, TCSETA, (char *)&tbuf); #else /* disable all of the special characters except the suspend char, interrupt char, and the control flow start/stop characters */ (void) ioctl(0, TIOCGLTC, (char *)&lbuf); lbuf.t_suspc = (char)26; /* control-Z */ lbuf.t_dsuspc = (char)-1; lbuf.t_rprntc = (char)-1; lbuf.t_flushc = (char)-1; lbuf.t_werasc = (char)-1; lbuf.t_lnextc = (char)-1; (void) ioctl(0, TIOCSLTC, (char *)&lbuf); (void) ioctl (0, TIOCGETC, (char *)&buf); buf.t_intrc = (char)3; /* control-C */ buf.t_quitc = (char)-1; buf.t_startc = (char)17; /* control-Q */ buf.t_stopc = (char)19; /* control-S */ buf.t_eofc = (char)-1; buf.t_brkc = (char)-1; (void) ioctl(0, TIOCSETC, (char *)&buf); #endif #endif #endif #endif #ifdef ATARIST_TC raw (); #endif } #endif /* Dump IO to buffer -RAK- */ void put_buffer(out_str, row, col) char *out_str; int row, col; #ifdef MAC { /* The screen manager handles writes past the edge ok */ DSetScreenCursor(col, row); DWriteScreenStringAttr(out_str, ATTR_NORMAL); } #else { vtype tmp_str; /* truncate the string, to make sure that it won't go past right edge of screen */ if (col > 79) col = 79; (void) strncpy (tmp_str, out_str, 79 - col); tmp_str [79 - col] = '\0'; if (mvaddstr(row, col, tmp_str) == ERR) { abort(); /* clear msg_flag to avoid problems with unflushed messages */ msg_flag = 0; (void) sprintf(tmp_str, "error in put_buffer, row = %d col = %d\n", row, col); prt(tmp_str, 0, 0); bell(); /* wait so user can see error */ (void) sleep(2); } } #endif /* Dump the IO buffer to terminal -RAK- */ void put_qio() { screen_change = TRUE; /* Let inven_command know something has changed. */ #ifdef MAC UpdateScreen(); #else (void) refresh(); #endif } /* Put the terminal in the original mode. -CJS- */ void restore_term() #ifdef MAC /* Nothing to do on Mac */ { } #else { #ifdef AMIGA closetimer (); #endif if (!curses_on) return; put_qio(); /* Dump any remaining buffer */ #ifdef MSDOS (void) sleep(2); /* And let it be read. */ #endif #ifdef VMS clear_screen(); pause_line(15); #endif /* this moves curses to bottom right corner */ mvcur(stdscr->_cury, stdscr->_curx, LINES-1, 0); endwin(); /* exit curses */ (void) fflush (stdout); #ifdef MSDOS msdos_noraw(); #endif /* restore the saved values of the special chars */ #ifdef USG #if !defined(MSDOS) && !defined(ATARI_ST) && !defined(VMS) #ifndef AMIGA (void) ioctl(0, TCSETA, (char *)&save_termio); #endif #endif #else (void) ioctl(0, TIOCSLTC, (char *)&save_special_chars); (void) ioctl(0, TIOCSETP, (char *)&save_ttyb); (void) ioctl(0, TIOCSETC, (char *)&save_tchars); #if !defined(atarist) && !defined(__GNUC__) (void) ioctl(0, TIOCLSET, (char *)&save_local_chars); #endif #endif curses_on = FALSE; } #endif void shell_out() #if defined(atarist) && defined(__GNUC__) { char fail_message[80], arg_list[1], *p; int escape_code; save_screen(); clear_screen(); use_value nocbreak(); /* Must remember to reset terminal modes */ use_value echo(); /* or shell i/o will be quite messed up! */ p = (char *)getenv("SHELL"); if (p != (char *)NULL) { put_buffer("Escaping to Shell\n",0,0); put_qio(); arg_list[0]=0; escape_code = Pexec(0,p,arg_list,0); /* Launch the shell. */ if (escape_code != 0) { sprintf(fail_message,"Pexec() error code = %d\n",escape_code); put_buffer(fail_message,0,0); put_qio(); sleep(5); } } use_value cbreak(); /* Reset the terminal back to CBREAK/NOECHO */ use_value noecho(); clear_screen(); /* Do not want shell data on screen. */ restore_screen(); } #else #ifdef MAC { alert_error("This command is not implemented on the Macintosh."); } #else #if defined(AMIGA) || defined(ATARIST_TC) { put_buffer("This command is not implemented.\n", 0, 0); } #else #ifdef VMS /* TPP */ { int val, istat; char *str; save_screen(); /* clear screen and print 'exit' message */ clear_screen(); put_buffer("[Entering subprocess, type 'EOJ' to resume your game.]\n", 0, 0); put_qio(); use_value vms_nocrmode(); use_value echo(); ignore_signals(); istat = lib$spawn(); if (!istat) lib$signal (istat); restore_signals(); use_value vms_crmode(); use_value noecho(); /* restore the cave to the screen */ restore_screen(); put_buffer("Welcome back to UMoria.\n", 0, 0); save_screen(); clear_screen(); put_qio(); restore_screen(); (void) wrefresh(curscr); } #else { #ifdef USG #if !defined(MSDOS) && !defined(ATARI_ST) && !defined(AMIGA) #ifdef __linux__ struct termios tbuf; #else struct termio tbuf; #endif #endif #else struct sgttyb tbuf; struct ltchars lcbuf; struct tchars cbuf; int lbuf; #endif #ifdef MSDOS char *comspec, key; #else #ifdef ATARI_ST char comstr[80]; char *str; extern char **environ; #else int val; char *str; #endif #endif save_screen(); /* clear screen and print 'exit' message */ clear_screen(); #ifndef ATARI_ST put_buffer("[Entering shell, type 'exit' to resume your game.]\n",0,0); #else put_buffer("[Escaping to shell]\n",0,0); #endif put_qio(); #ifdef USG #if !defined(MSDOS) && !defined(ATARI_ST) && !defined(AMIGA) (void) ioctl(0, TCGETA, (char *)&tbuf); #endif #else (void) ioctl(0, TIOCGETP, (char *)&tbuf); (void) ioctl(0, TIOCGETC, (char *)&cbuf); (void) ioctl(0, TIOCGLTC, (char *)&lcbuf); (void) ioctl(0, TIOCLGET, (char *)&lbuf); #endif /* would call nl() here if could use nl()/nonl(), see moriaterm() */ #ifndef BSD4_3 use_value nocrmode(); #else #ifdef VMS use_value vms_nocrmode (); #else use_value nocbreak(); #endif #endif #ifdef MSDOS use_value msdos_noraw(); #endif use_value echo(); ignore_signals(); #ifdef MSDOS /*{*/ if ((comspec = getenv("COMSPEC")) == CNIL || spawnl(P_WAIT, comspec, comspec, CNIL) < 0) { clear_screen(); /* BOSS key if shell failed */ put_buffer("M:\\> ", 0, 0); do { key = inkey(); } while (key != '!'); } #else /* MSDOS }{*/ #ifndef ATARI_ST val = fork(); if (val == 0) { #endif default_signals(); #ifdef USG #if !defined(MSDOS) && !defined(ATARI_ST) && !defined(AMIGA) (void) ioctl(0, TCSETA, (char *)&save_termio); #endif #else (void) ioctl(0, TIOCSLTC, (char *)&save_special_chars); (void) ioctl(0, TIOCSETP, (char *)&save_ttyb); (void) ioctl(0, TIOCSETC, (char *)&save_tchars); (void) ioctl(0, TIOCLSET, (char *)&save_local_chars); #endif #ifndef MSDOS /* close scoreboard descriptor */ /* it is not open on MSDOS machines */ (void) fclose(highscore_fp); #endif if (str = getenv("SHELL")) #ifndef ATARI_ST (void) execl(str, str, (char *) 0); #else system(str); #endif else #ifndef ATARI_ST (void) execl("/bin/sh", "sh", (char *) 0); #endif msg_print("Cannot execute shell."); #ifndef ATARI_ST exit(1); } if (val == -1) { msg_print("Fork failed. Try again."); return; } #if defined(USG) || defined(__386BSD__) (void) wait((int *) 0); #else (void) wait((union wait *) 0); #endif #endif /* ATARI_ST */ #endif /* MSDOS }*/ restore_signals(); /* restore the cave to the screen */ restore_screen(); #ifndef BSD4_3 use_value crmode(); #else #ifdef VMS use_value vms_crmode (); #else use_value cbreak(); #endif #endif use_value noecho(); /* would call nonl() here if could use nl()/nonl(), see moriaterm() */ #ifdef MSDOS msdos_raw(); #endif /* disable all of the local special characters except the suspend char */ /* have to disable ^Y for tunneling */ #ifdef USG #if !defined(MSDOS) && !defined(ATARI_ST) (void) ioctl(0, TCSETA, (char *)&tbuf); #endif #else (void) ioctl(0, TIOCSLTC, (char *)&lcbuf); (void) ioctl(0, TIOCSETP, (char *)&tbuf); (void) ioctl(0, TIOCSETC, (char *)&cbuf); (void) ioctl(0, TIOCLSET, (char *)&lbuf); #endif (void) wrefresh(curscr); } #endif #endif #endif #endif /* Returns a single character input from the terminal. This silently -CJS- consumes ^R to redraw the screen and reset the terminal, so that this operation can always be performed at any input prompt. inkey() never returns ^R. */ char inkey() #ifdef MAC /* The Mac does not need ^R, so it just consumes it */ /* This routine does nothing special with direction keys */ /* Just returns their keypad ascii value (e.g. '0'-'9') */ /* Compare with inkeydir() below */ { char ch; int dir; int shift_flag, ctrl_flag; put_qio(); command_count = 0; do { macgetkey(&ch, FALSE); } while (ch == CTRL('R')); dir = extractdir(ch, &shift_flag, &ctrl_flag); if (dir != -1) ch = '0' + dir; return(ch); } #else { int i; #ifdef VMS vtype tmp_str; #endif put_qio(); /* Dump IO buffer */ command_count = 0; /* Just to be safe -CJS- */ while (TRUE) { #ifdef MSDOS i = msdos_getch(); #else #ifdef VMS i = vms_getch (); #else i = getch(); #if defined(atarist) && defined(__GNUC__) /* for some reason a keypad number produces an initial negative number. */ if (i<0) i = getch(); #endif #endif #endif #ifdef VMS if (i == 27) /* if ESCAPE key, then we probably have a keypad key */ { i = vms_getch(); if (i == 'O') /* Now it is definitely a numeric keypad key */ { i = vms_getch(); switch (i) { case 'p': i = '0'; break; case 'q' : i = '1'; break; case 'r' : i = '2'; break; case 's' : i = '3'; break; case 't' : i = '4'; break; case 'u' : i = '5'; break; case 'v' : i = '6'; break; case 'w' : i = '7'; break; case 'x' : i = '8'; break; case 'y' : i = '9'; break; case 'm' : i = '-'; break; case 'M' : i = 10; break; /* Enter = RETURN */ case 'n' : i = '.'; break; default : while (kbhit()) (void) vms_getch(); } } else { while (kbhit()) (void) vms_getch(); } } #endif /* VMS */ /* some machines may not sign extend. */ if (i == EOF) { eof_flag++; /* avoid infinite loops while trying to call inkey() for a -more- prompt. */ msg_flag = FALSE; (void) refresh (); if (!character_generated || character_saved) exit_game(); disturb(1, 0); if (eof_flag > 100) { /* just in case, to make sure that the process eventually dies */ panic_save = 1; (void) strcpy(died_from, "(end of input: panic saved)"); if (!save_char()) { (void) strcpy(died_from, "panic: unexpected eof"); death = TRUE; } exit_game(); } return ESCAPE; } if (i != CTRL('R')) return (char)i; #ifdef VMS /* Refresh does not work right under VMS, so use a brute force. */ overwrite (stdscr, tempscr); clear_screen(); put_qio(); overwrite (tempscr, stdscr); touchwin (stdscr); (void) wrefresh (stdscr); #endif (void) wrefresh (curscr); moriaterm(); } } #endif #ifdef MAC char inkeydir() /* The Mac does not need ^R, so it just consumes it */ /* This routine translates the direction keys in rogue-like mode */ /* Compare with inkeydir() below */ { char ch; int dir; int shift_flag, ctrl_flag; static char tab[9] = { 'b', 'j', 'n', 'h', '.', 'l', 'y', 'k', 'u' }; static char shifttab[9] = { 'B', 'J', 'N', 'H', '.', 'L', 'Y', 'K', 'U' }; static char ctrltab[9] = { CTRL('B'), CTRL('J'), CTRL('N'), CTRL('H'), '.', CTRL('L'), CTRL('Y'), CTRL('K'), CTRL('U') }; put_qio(); command_count = 0; do { macgetkey(&ch, FALSE); } while (ch == CTRL('R')); dir = extractdir(ch, &shift_flag, &ctrl_flag); if (dir != -1) { if (!rogue_like_commands) { ch = '0' + dir; } else { if (ctrl_flag) ch = ctrltab[dir - 1]; else if (shift_flag) ch = shifttab[dir - 1]; else ch = tab[dir - 1]; } } return(ch); } #endif /* Flush the buffer -RAK- */ void flush() #ifdef MAC { /* Removed put_qio() call. Reduces flashing. Doesn't seem to hurt. */ FlushScreenKeys(); } #else { #if defined(MSDOS) while (kbhit()) (void) getch(); #else #ifdef VMS while (kbhit ()) (void) vms_getch(); #else /* the code originally used ioctls, TIOCDRAIN, or TIOCGETP/TIOCSETP, or TCGETA/TCSETAF, however this occasionally resulted in loss of output, the happened especially often when rlogin from BSD to SYS_V machine, using check_input makes the desired effect a bit clearer */ /* wierd things happen on EOF, don't try to flush input in that case */ if (!eof_flag) while (check_input(0)); #endif #endif /* used to call put_qio() here to drain output, but it is not necessary */ } #endif /* Clears given line of text -RAK- */ void erase_line(row, col) int row; int col; #ifdef MAC { Rect line; if (row == MSG_LINE && msg_flag) msg_print(CNIL); line.left = col; line.top = row; line.right = SCRN_COLS; line.bottom = row + 1; DEraseScreen(&line); } #else { if (row == MSG_LINE && msg_flag) msg_print(CNIL); (void) move(row, col); clrtoeol(); } #endif /* Clears screen */ void clear_screen() #ifdef MAC { Rect area; if (msg_flag) msg_print(CNIL); area.left = area.top = 0; area.right = SCRN_COLS; area.bottom = SCRN_ROWS; DEraseScreen(&area); } #else { if (msg_flag) msg_print(CNIL); #ifdef VMS /* Clear doesn't work right under VMS, so use brute force. */ (void) clearok (stdscr, TRUE); (void) wclear(stdscr); (void) clearok (stdscr, FALSE); #else (void) clear(); #endif } #endif void clear_from (row) int row; #ifdef MAC { Rect area; area.left = 0; area.top = row; area.right = SCRN_COLS; area.bottom = SCRN_ROWS; DEraseScreen(&area); } #else { (void) move(row, 0); clrtobot(); } #endif /* Outputs a char to a given interpolated y, x position -RAK- */ /* sign bit of a character used to indicate standout mode. -CJS */ void print(ch, row, col) char ch; int row; int col; #ifdef MAC { char cnow, anow; row -= panel_row_prt;/* Real co-ords convert to screen positions */ col -= panel_col_prt; GetScreenCharAttr(&cnow, &anow, col, row); /* Check current */ /* If char is already set, ignore op */ if ((cnow != ch) || (anow != ATTR_NORMAL)) DSetScreenCharAttr(ch & 0x7F, (ch & 0x80) ? attrReversed : attrNormal, col, row); } #else { vtype tmp_str; row -= panel_row_prt;/* Real co-ords convert to screen positions */ col -= panel_col_prt; if (mvaddch (row, col, ch) == ERR) { abort(); /* clear msg_flag to avoid problems with unflushed messages */ msg_flag = 0; (void) sprintf(tmp_str, "error in print, row = %d col = %d\n", row, col); prt(tmp_str, 0, 0); bell (); /* wait so user can see error */ (void) sleep(2); } } #endif /* Moves the cursor to a given interpolated y, x position -RAK- */ void move_cursor_relative(row, col) int row; int col; #ifdef MAC { row -= panel_row_prt;/* Real co-ords convert to screen positions */ col -= panel_col_prt; DSetScreenCursor(col, row); } #else { vtype tmp_str; row -= panel_row_prt;/* Real co-ords convert to screen positions */ col -= panel_col_prt; if (move (row, col) == ERR) { abort(); /* clear msg_flag to avoid problems with unflushed messages */ msg_flag = 0; (void) sprintf(tmp_str, "error in move_cursor_relative, row = %d col = %d\n", row, col); prt(tmp_str, 0, 0); bell(); /* wait so user can see error */ (void) sleep(2); } } #endif /* Print a message so as not to interrupt a counted command. -CJS- */ void count_msg_print(p) char *p; { int i; i = command_count; msg_print(p); command_count = i; } /* Outputs a line to a given y, x position -RAK- */ void prt(str_buff, row, col) char *str_buff; int row; int col; #ifdef MAC { Rect line; if (row == MSG_LINE && msg_flag) msg_print(CNIL); line.left = col; line.top = row; line.right = SCRN_COLS; line.bottom = row + 1; DEraseScreen(&line); put_buffer(str_buff, row, col); } #else { if (row == MSG_LINE && msg_flag) msg_print(CNIL); (void) move(row, col); clrtoeol(); put_buffer(str_buff, row, col); } #endif /* move cursor to a given y, x position */ void move_cursor(row, col) int row, col; #ifdef MAC { DSetScreenCursor(col, row); } #else { (void) move (row, col); } #endif /* Outputs message to top line of screen */ /* These messages are kept for later reference. */ void msg_print(str_buff) char *str_buff; { register int old_len, new_len; int combine_messages = FALSE; char in_char; #ifdef MAC Rect line; #endif if (msg_flag) { old_len = strlen(old_msg[last_msg]) + 1; /* If the new message and the old message are short enough, we want display them together on the same line. So we don't flush the old message in this case. */ if (str_buff) new_len = strlen (str_buff); else new_len = 0; if (! str_buff || (new_len + old_len + 2 >= 73)) { /* ensure that the complete -more- message is visible. */ if (old_len > 73) old_len = 73; put_buffer(" -more-", MSG_LINE, old_len); /* let sigint handler know that we are waiting for a space */ wait_for_more = 1; do { in_char = inkey(); } while ((in_char != ' ') && (in_char != ESCAPE) && (in_char != '\n') && (in_char != '\r')); wait_for_more = 0; } else combine_messages = TRUE; } if (! combine_messages) { #ifdef MAC line.left = 0; line.top = MSG_LINE; line.right = SCRN_COLS; line.bottom = MSG_LINE+1; DEraseScreen(&line); #else (void) move(MSG_LINE, 0); clrtoeol(); #endif } /* Make the null string a special case. -CJS- */ if (str_buff) { command_count = 0; msg_flag = TRUE; /* If the new message and the old message are short enough, display them on the same line. */ if (combine_messages) { put_buffer (str_buff, MSG_LINE, old_len + 2); strcat (old_msg[last_msg], " "); strcat (old_msg[last_msg], str_buff); } else { put_buffer(str_buff, MSG_LINE, 0); last_msg++; if (last_msg >= MAX_SAVE_MSG) last_msg = 0; (void) strncpy(old_msg[last_msg], str_buff, VTYPESIZ); old_msg[last_msg][VTYPESIZ - 1] = '\0'; } } else msg_flag = FALSE; } /* Used to verify a choice - user gets the chance to abort choice. -CJS- */ int get_check(prompt) char *prompt; { int res; #ifdef MAC long y, x; /* ??? Should change to int or short. */ #else int y, x; #endif prt(prompt, 0, 0); #ifdef MAC GetScreenCursor(&x, &y); #else getyx(stdscr, y, x); #if defined(lint) /* prevent message 'warning: y is unused' */ x = y; #endif #ifdef LINT_ARGS /* prevent message about y never used for MSDOS systems */ res = y; #endif #endif if (x > 73) (void) move(0, 73); #ifdef MAC DWriteScreenStringAttr(" [y/n]", ATTR_NORMAL); #else (void) addstr(" [y/n]"); #endif do { res = inkey(); } while(res == ' '); erase_line(0, 0); if (res == 'Y' || res == 'y') return TRUE; else return FALSE; } /* Prompts (optional) and returns ord value of input char */ /* Function returns false if is input */ int get_com(prompt, command) char *prompt; char *command; { int res; if (prompt) prt(prompt, 0, 0); *command = inkey(); if (*command == ESCAPE) res = FALSE; else res = TRUE; erase_line(MSG_LINE, 0); return(res); } #ifdef MAC /* Same as get_com(), but translates direction keys from keypad */ int get_comdir(prompt, command) char *prompt; char *command; { int res; if (prompt) prt(prompt, 0, 0); *command = inkeydir(); if (*command == ESCAPE) res = FALSE; else res = TRUE; erase_line(MSG_LINE, 0); return(res); } #endif /* Gets a string terminated by */ /* Function returns false if is input */ int get_string(in_str, row, column, slen) char *in_str; int row, column, slen; { register int start_col, end_col, i; char *p; int flag, aborted; #ifdef MAC Rect area; #endif aborted = FALSE; flag = FALSE; #ifdef MAC area.left = column; area.top = row; area.right = column + slen; area.bottom = row + 1; DEraseScreen(&area); DSetScreenCursor(column, row); #else (void) move(row, column); for (i = slen; i > 0; i--) (void) addch(' '); (void) move(row, column); #endif start_col = column; end_col = column + slen - 1; if (end_col > 79) { slen = 80 - column; end_col = 79; } p = in_str; do { i = inkey(); switch(i) { case ESCAPE: aborted = TRUE; break; case CTRL('J'): case CTRL('M'): flag = TRUE; break; case DELETE: case CTRL('H'): if (column > start_col) { column--; put_buffer(" ", row, column); move_cursor(row, column); *--p = '\0'; } break; default: if (!isprint(i) || column > end_col) bell(); else { #ifdef MAC DSetScreenCursor(column, row); DWriteScreenCharAttr((char) i, ATTR_NORMAL); #else use_value2 mvaddch(row, column, (char)i); #endif *p++ = i; column++; } break; } } while ((!flag) && (!aborted)); if (aborted) return(FALSE); /* Remove trailing blanks */ while (p > in_str && p[-1] == ' ') p--; *p = '\0'; return(TRUE); } /* Pauses for user response before returning -RAK- */ void pause_line(prt_line) int prt_line; { prt("[Press any key to continue.]", prt_line, 23); (void) inkey(); erase_line(prt_line, 0); } /* Pauses for user response before returning -RAK- */ /* NOTE: Delay is for players trying to roll up "perfect" */ /* characters. Make them wait a bit. */ void pause_exit(prt_line, delay) int prt_line; int delay; { char dummy; prt("[Press any key to continue, or Q to exit.]", prt_line, 10); dummy = inkey(); if (dummy == 'Q') { erase_line(prt_line, 0); #ifndef MSDOS /* PCs are slow enough as is -dgk */ if (delay > 0) (void) sleep((unsigned)delay); #else /* prevent message about delay unused */ dummy = delay; #endif #ifdef MAC enablefilemenu(FALSE); exit_game(); enablefilemenu(TRUE); #else exit_game(); #endif } erase_line(prt_line, 0); } #ifdef MAC void save_screen() { mac_save_screen(); } void restore_screen() { mac_restore_screen(); } #else void save_screen() { overwrite(stdscr, savescr); } void restore_screen() { overwrite(savescr, stdscr); touchwin(stdscr); } #endif void bell() { put_qio(); /* The player can turn off beeps if he/she finds them annoying. */ if (! sound_beep_flag) return; #ifdef MAC mac_beep(); #else (void) write(1, "\007", 1); #endif } /* definitions used by screen_map() */ /* index into border character array */ #define TL 0 /* top left */ #define TR 1 #define BL 2 #define BR 3 #define HE 4 /* horizontal edge */ #define VE 5 /* character set to use */ #ifdef MSDOS # ifdef ANSI # define CH(x) (ansi ? screen_border[0][x] : screen_border[1][x]) # else # define CH(x) (screen_border[1][x]) # endif #else # define CH(x) (screen_border[0][x]) #endif /* Display highest priority object in the RATIO by RATIO area */ #define RATIO 3 void screen_map() { register int i, j; static int8u screen_border[2][6] = { {'+', '+', '+', '+', '-', '|'}, /* normal chars */ {201, 187, 200, 188, 205, 186} /* graphics chars */ }; int8u map[MAX_WIDTH / RATIO + 1]; int8u tmp; int priority[256]; int row, orow, col, myrow, mycol = 0; #ifndef MAC char prntscrnbuf[80]; #endif for (i = 0; i < 256; i++) priority[i] = 0; priority['<'] = 5; priority['>'] = 5; priority['@'] = 10; #ifdef MSDOS priority[wallsym] = -5; priority[floorsym] = -10; #else #ifndef ATARI_ST priority['#'] = -5; #else priority[(unsigned char)240] = -5; #endif priority['.'] = -10; #endif priority['\''] = -3; priority[' '] = -15; save_screen(); clear_screen(); #ifdef MAC DSetScreenCursor(0, 0); DWriteScreenCharAttr(CH(TL), ATTR_NORMAL); for (i = 0; i < MAX_WIDTH / RATIO; i++) DWriteScreenCharAttr(CH(HE), ATTR_NORMAL); DWriteScreenCharAttr(CH(TR), ATTR_NORMAL); #else use_value2 mvaddch(0, 0, CH(TL)); for (i = 0; i < MAX_WIDTH / RATIO; i++) (void) addch(CH(HE)); (void) addch(CH(TR)); #endif orow = -1; map[MAX_WIDTH / RATIO] = '\0'; for (i = 0; i < MAX_HEIGHT; i++) { row = i / RATIO; if (row != orow) { if (orow >= 0) { #ifdef MAC DSetScreenCursor(0, orow+1); DWriteScreenCharAttr(CH(VE), ATTR_NORMAL); DWriteScreenString((char *) map); DWriteScreenCharAttr(CH(VE), ATTR_NORMAL); #else /* can not use mvprintw() on ibmpc, because PC-Curses is horribly written, and mvprintw() causes the fp emulation library to be linked with PC-Moria, makes the program 10K bigger */ (void) sprintf(prntscrnbuf,"%c%s%c",CH(VE), map, CH(VE)); use_value2 mvaddstr(orow+1, 0, prntscrnbuf); #endif } for (j = 0; j < MAX_WIDTH / RATIO; j++) map[j] = ' '; orow = row; } for (j = 0; j < MAX_WIDTH; j++) { col = j / RATIO; tmp = loc_symbol(i, j); if (priority[map[col]] < priority[tmp]) map[col] = tmp; if (map[col] == '@') { mycol = col + 1; /* account for border */ myrow = row + 1; } } } if (orow >= 0) { #ifdef MAC DSetScreenCursor(0, orow+1); DWriteScreenCharAttr(CH(VE), ATTR_NORMAL); DWriteScreenString((char *) map); DWriteScreenCharAttr(CH(VE), ATTR_NORMAL); #else (void) sprintf(prntscrnbuf,"%c%s%c",CH(VE), map, CH(VE)); use_value2 mvaddstr(orow+1, 0, prntscrnbuf); #endif } #ifdef MAC DSetScreenCursor(0, orow + 2); DWriteScreenCharAttr(CH(BL), ATTR_NORMAL); for (i = 0; i < MAX_WIDTH / RATIO; i++) DWriteScreenCharAttr(CH(HE), ATTR_NORMAL); DWriteScreenCharAttr(CH(BR), ATTR_NORMAL); #else use_value2 mvaddch(orow + 2, 0, CH(BL)); for (i = 0; i < MAX_WIDTH / RATIO; i++) (void) addch(CH(HE)); (void) addch(CH(BR)); #endif #ifdef MAC DSetScreenCursor(23, 23); DWriteScreenStringAttr("Hit any key to continue", ATTR_NORMAL); if (mycol > 0) DSetScreenCursor(mycol, myrow); #else use_value2 mvaddstr(23, 23, "Hit any key to continue"); if (mycol > 0) (void) move(myrow, mycol); #endif (void) inkey(); restore_screen(); } moria-5.6.debian.1/source/monsters.c0000644000175000017500000012062211074756544015521 0ustar pjbpjb/* source/monsters.c: monster definitions Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include "config.h" #include "constant.h" #include "types.h" /* Following are creature arrays and variables */ /* Creatures must be defined here */ /* See types.h under creature_type for a complete list of all variables for creatures. Some of the less obvious are explained below. Hit points: #1, #2: where #2 is the range of each roll and #1 is the number of added up rolls to make. Example: a creature with 5 eight-sided hit die is given {5,8}. Attack types: 1 Normal attack 2 Poison Strength 3 Confusion attack 4 Fear attack 5 Fire attack 6 Acid attack 7 Cold attack 8 Lightning attack 9 Corrosion attack 10 Blindness attack 11 Paralysis attack 12 Steal Money 13 Steal Object 14 Poison 15 Lose dexterity 16 Lose constitution 17 Lose intelligence 18 Lose wisdom 19 Lose experience 20 Aggravation 21 Disenchants 22 Eats food 23 Eats light 24 Eats charges 99 Blank Attack descriptions: 1 hits you. 2 bites you. 3 claws you. 4 stings you. 5 touches you. 6 kicks you. 7 gazes at you. 8 breathes on you. 9 spits on you. 10 makes a horrible wail. 11 embraces you. 12 crawls on you. 13 releases a cloud of spores. 14 begs you for money. 15 You've been slimed. 16 crushes you. 17 tramples you. 18 drools on you. 19 insults you. 99 is repelled. Example: For a creature which bites for 1d6, then stings for 2d4 and loss of dex you would use: {1,2,1,6},{15,4,2,4} CMOVE flags: Movement. 00000001 Move only to attack . 00000002 Move, attack normal . 00000008 20% random movement . 00000010 40% random movement . 00000020 75% random movement Special + 00010000 Invisible movement + 00020000 Move through door + 00040000 Move through wall + 00080000 Move through creatures + 00100000 Picks up objects + 00200000 Multiply monster Carries = 01000000 Carries objects. = 02000000 Carries gold. = 04000000 Has 60% of time. = 08000000 Has 90% of time. = 10000000 1d2 objects/gold. = 20000000 2d2 objects/gold. = 40000000 4d2 objects/gold. Special ~ 80000000 Win-the-Game creature. SPELL Flags: Frequency 000001 1 These add up to x. Then (1 in x). 000002 2 if RANDINT(X) = 1 the . 000004 4 creature casts a spell. . 000008 8 Spells = 000010 Teleport short (blink) = 000020 Teleport long = 000040 Teleport player to monster = 000080 Cause light wound = 000100 Cause serious wound = 000200 Hold person (Paralysis) = 000400 Cause blindness = 000800 Cause confusion = 001000 Cause fear = 002000 Summon monster = 004000 Summon undead = 008000 Slow Person = 010000 Drain Mana = 020000 Not Used = 040000 Not Used Breath/ + 080000 Breathe/Resist Lightning Resist + 100000 Breathe/Resist Gas + 200000 Breathe/Resist Acid + 400000 Breathe/Resist Frost + 800000 Breathe/Resist Fire CDEFENSE flags: 0001 Hurt by Slay Dragon. 0002 Hurt by Slay Animal. 0004 Hurt by Slay Evil. 0008 Hurt by Slay Undead. 0010 Hurt by Frost. 0020 Hurt by Fire. 0040 Hurt by Poison. 0080 Hurt by Acid. 0100 Hurt by Light-Wand. 0200 Hurt by Stone-to-Mud. 0400 Not used. 0800 Not used. 1000 Cannot be charmed or slept. 2000 Can be seen with infra-vision. 4000 Max Hit points. 8000 Not used. Sleep (sleep) : A measure in turns of how fast creature will notice player (on the average). Area of affect (aaf) : Max range that creature is able to "notice" the player. */ #ifdef MACGAME creature_type *c_list; #else creature_type c_list[MAX_CREATURES] = { {"Filthy Street Urchin" ,0x0012000AL,0x00000000L,0x2034, 0, 40, 4, 1, 11, 'p', {1,4} , {72,148,0,0} , 0}, {"Blubbering Idiot" ,0x0012000AL,0x00000000L,0x2030, 0, 0, 6, 1, 11, 'p', {1,2} , {79,0,0,0} , 0}, {"Pitiful-Looking Beggar" ,0x0012000AL,0x00000000L,0x2030, 0, 40, 10, 1, 11, 'p', {1,4} , {72,0,0,0} , 0}, {"Mangy-Looking Leper" ,0x0012000AL,0x00000000L,0x2030, 0, 50, 10, 1, 11, 'p', {1,1} , {72,0,0,0} , 0}, {"Squint-Eyed Rogue" ,0x07120002L,0x00000000L,0x2034, 0, 99, 10, 8, 11, 'p', {2,8} , {5,149,0,0} , 0}, {"Singing, Happy Drunk" ,0x06120038L,0x00000000L,0x2030, 0, 0, 10, 1, 11, 'p', {2,3} , {72,0,0,0} , 0}, {"Mean-Looking Mercenary" ,0x0B12000AL,0x00000000L,0x2034, 0, 250, 10, 20, 11, 'p', {5,8} , {9,0,0,0} , 0}, {"Battle-Scarred Veteran" ,0x0B12000AL,0x00000000L,0x2030, 0, 250, 10, 30, 11, 'p', {7,8} , {15,0,0,0} , 0}, {"Grey Mushroom patch" ,0x00000001L,0x00000000L,0x10A0, 1, 0, 2, 1, 11, ',', {1,2} , {91,0,0,0} , 1}, {"Giant Yellow Centipede" ,0x00000002L,0x00000000L,0x0002, 2, 30, 8, 12, 11, 'c', {2,6} , {26,60,0,0} , 1}, {"Giant White Centipede" ,0x0000000AL,0x00000000L,0x0002, 2, 40, 7, 10, 11, 'c', {3,5} , {25,59,0,0} , 1}, {"White Icky-Thing" ,0x00000012L,0x00000000L,0x0020, 2, 10, 12, 7, 11, 'i', {3,5} , {63,0,0,0} , 1}, {"Clear Icky-Thing" ,0x00010012L,0x00000000L,0x0020, 1, 10, 12, 6, 11, 'i', {2,5} , {63,0,0,0} , 1}, {"Giant White Mouse" ,0x0020000AL,0x00000000L,0x2072, 1, 20, 8, 4, 11, 'r', {1,3} , {25,0,0,0} , 1}, {"Large Brown Snake" ,0x0000000AL,0x00000000L,0x00B2, 3, 99, 4, 35, 10, 'R', {4,6} , {26,73,0,0} , 1}, {"Large White Snake" ,0x00000012L,0x00000000L,0x00B2, 2, 99, 4, 30, 11, 'R', {3,6} , {24,0,0,0} , 1}, {"Kobold" ,0x07820002L,0x00000000L,0x2030, 5, 10, 20, 16, 11, 'k', {3,7} , {5,0,0,0} , 1}, {"White Worm mass" ,0x00200022L,0x00000000L,0x01B2, 2, 10, 7, 1, 10, 'w', {4,4} , {173,0,0,0} , 1}, {"Floating Eye" ,0x00000001L,0x0001000DL,0x2100, 1, 10, 2, 6, 11, 'e', {3,6} , {146,0,0,0} , 1}, {"Shrieker Mushroom patch" ,0x00000001L,0x00000000L,0x10A0, 1, 0, 2, 1, 11, ',', {1,1} , {203,0,0,0} , 2}, {"Blubbering Icky-Thing" ,0x0B980012L,0x00000000L,0x0020, 8, 10, 14, 4, 11, 'i', {5,8} , {174,210,0,0} , 2}, {"Metallic Green Centipede" ,0x00000012L,0x00000000L,0x0002, 3, 10, 5, 4, 12, 'c', {4,4} , {68,0,0,0} , 2}, {"Novice Warrior" ,0x07020002L,0x00000000L,0x2030, 6, 5, 20, 16, 11, 'p', {9,4} , {6,0,0,0} , 2}, {"Novice Rogue" ,0x07120002L,0x00000000L,0x2034, 6, 5, 20, 12, 11, 'p', {8,4} , {5,148,0,0} , 2}, {"Novice Priest" ,0x07020002L,0x0000108CL,0x2030, 7, 5, 20, 10, 11, 'p', {7,4} , {4,0,0,0} , 2}, {"Novice Mage" ,0x07020002L,0x0000089CL,0x2030, 7, 5, 20, 6, 11, 'p', {6,4} , {3,0,0,0} , 2}, {"Yellow Mushroom patch" ,0x00000001L,0x00000000L,0x10A0, 2, 0, 2, 1, 11, ',', {1,1} , {100,0,0,0} , 2}, {"White Jelly" ,0x00000001L,0x00000000L,0x11A0, 10, 99, 2, 1, 12, 'J', {8,8} , {168,0,0,0} , 2}, {"Giant Green Frog" ,0x0000000AL,0x00000000L,0x00A2, 6, 30, 12, 8, 11, 'f', {2,8} , {26,0,0,0} , 2}, {"Giant Black Ant" ,0x0000000AL,0x00000000L,0x0002, 8, 80, 8, 20, 11, 'a', {3,6} , {27,0,0,0} , 2}, {"White Harpy" ,0x00000012L,0x00000000L,0x2034, 5, 10, 16, 17, 11, 'h', {2,5} , {49,49,25,0} , 2}, {"Blue Yeek" ,0x07020002L,0x00000000L,0x2030, 4, 10, 18, 14, 11, 'y', {2,6} , {4,0,0,0} , 2}, {"Green Worm mass" ,0x00200022L,0x00000000L,0x0132, 3, 10, 7, 3, 10, 'w', {6,4} , {140,0,0,0} , 2}, {"Large Black Snake" ,0x0000000AL,0x00000000L,0x00B2, 9, 75, 5, 38, 10, 'R', {4,8} , {27,74,0,0} , 2}, {"Poltergeist" ,0x0F95003AL,0x0000001FL,0x110C, 6, 10, 8, 15, 13, 'G', {2,5} , {93,0,0,0} , 3}, {"Metallic Blue Centipede" ,0x00000012L,0x00000000L,0x0002, 7, 15, 6, 6, 12, 'c', {4,5} , {69,0,0,0} , 3}, {"Giant White Louse" ,0x00200022L,0x00000000L,0x01F2, 1, 10, 6, 5, 12, 'l', {1,1} , {24,0,0,0} , 3}, {"Black Naga" ,0x0710000AL,0x00000000L,0x20E4, 20, 120, 16, 40, 11, 'n', {6,8} , {75,0,0,0} , 3}, {"Spotted Mushroom patch" ,0x00000001L,0x00000000L,0x10A0, 3, 0, 2, 1, 11, ',', {1,1} , {175,0,0,0} , 3}, {"Yellow Jelly" ,0x00000001L,0x0001000FL,0x11A0, 12, 99, 2, 1, 12, 'J', {10,8} , {169,0,0,0} , 3}, {"Scruffy-Looking Hobbit" ,0x07920002L,0x00000000L,0x2034, 4, 10, 16, 8, 11, 'p', {3,5} , {3,148,0,0} , 3}, {"Huge Brown Bat" ,0x00000022L,0x00000000L,0x2162, 4, 40, 8, 12, 13, 'b', {2,6} , {25,0,0,0} , 3}, {"Giant White Ant" ,0x00000002L,0x00000000L,0x0002, 7, 80, 8, 16, 11, 'a', {3,6} , {27,0,0,0} , 3}, {"Yellow Mold" ,0x00000001L,0x00000000L,0x10A0, 9, 99, 2, 10, 11, 'm', {8,8} , {3,0,0,0} , 3}, {"Metallic Red Centipede" ,0x0000000AL,0x00000000L,0x0002, 12, 20, 8, 9, 12, 'c', {4,8} , {69,0,0,0} , 3}, {"Yellow Worm mass" ,0x00200022L,0x00000000L,0x01B2, 4, 10, 7, 4, 10, 'w', {4,8} , {182,0,0,0} , 3}, {"Large Green Snake" ,0x0000000AL,0x00000000L,0x00B2, 10, 70, 5, 40, 10, 'R', {6,8} , {27,74,0,0} , 3}, {"Radiation Eye" ,0x00000001L,0x0001000BL,0x2100, 6, 10, 2, 6, 11, 'e', {3,6} , {88,0,0,0} , 3}, {"Drooling Harpy" ,0x00000012L,0x00000000L,0x2034, 7, 10, 16, 22, 11, 'h', {2,8} , {49,49,25,79} , 3}, {"Silver Mouse" ,0x0020000AL,0x00000000L,0x0072, 1, 10, 8, 5, 11, 'r', {1,1} , {212,0,0,0} , 4}, {"Black Mushroom patch" ,0x00000001L,0x00000000L,0x10A0, 8, 0, 2, 1, 11, ',', {8,8} , {71,0,0,0} , 4}, {"Blue Jelly" ,0x00000001L,0x00400000L,0x11A0, 14, 99, 2, 1, 11, 'J', {12,8} , {125,0,0,0} , 4}, {"Creeping Copper Coins" ,0x12000002L,0x00000000L,0x1000, 9, 10, 3, 24, 10, '$', {7,8} , {3,170,0,0} , 4}, {"Giant White Rat" ,0x0020000AL,0x00000000L,0x2072, 1, 30, 8, 7, 11, 'r', {2,2} , {153,0,0,0} , 4}, {"Giant Black Centipede" ,0x0000000AL,0x00000000L,0x0002, 11, 30, 8, 20, 11, 'c', {5,8} , {25,59,0,0} , 4}, {"Giant Blue Centipede" ,0x00000002L,0x00000000L,0x0002, 10, 50, 8, 20, 11, 'c', {4,8} , {26,61,0,0} , 4}, {"Blue Worm mass" ,0x00200022L,0x00400000L,0x01A2, 5, 10, 7, 12, 10, 'w', {5,8} , {129,0,0,0} , 4}, {"Large Grey Snake" ,0x0000000AL,0x00000000L,0x00B2, 14, 50, 6, 41, 10, 'R', {6,8} , {28,75,0,0} , 4}, {"Jackal" ,0x00000012L,0x00000000L,0x2032, 8, 30, 12, 16, 11, 'j', {3,8} , {29,0,0,0} , 4}, {"Green Naga" ,0x0710000AL,0x00200000L,0x2064, 30, 120, 18, 40, 11, 'n', {9,8} , {75,118,0,0} , 5}, {"Green Glutton Ghost" ,0x0F950032L,0x0000003FL,0x110C, 15, 10, 10, 20, 13, 'G', {3,6} , {211,0,0,0} , 5}, {"White Mushroom patch" ,0x00000001L,0x00000000L,0x10A0, 5, 0, 2, 1, 11, ',', {1,1} , {147,0,0,0} , 5}, {"Green Jelly" ,0x00000001L,0x00200000L,0x1120, 18, 99, 2, 1, 12, 'J', {22,8} , {136,0,0,0} , 5}, {"Skeleton Kobold" ,0x00020002L,0x00000000L,0x100C, 12, 40, 20, 26, 11, 's', {5,8} , {5,0,0,0} , 5}, {"Silver Jelly" ,0x00000001L,0x00000000L,0x10A0, 15, 40, 2, 25, 11, 'J', {20,8} , {213,0,0,0} , 5}, {"Giant Black Frog" ,0x0000000AL,0x00000000L,0x00A2, 12, 40, 12, 18, 11, 'f', {4,8} , {29,0,0,0} , 5}, {"Grey Icky-Thing" ,0x00000012L,0x00000000L,0x0020, 10, 15, 14, 12, 11, 'i', {4,8} , {66,0,0,0} , 5}, {"Disenchanter Eye" ,0x00000001L,0x00010009L,0x2100, 20, 10, 2, 10, 10, 'e', {7,8} , {207,0,0,0} , 5}, {"Black Yeek" ,0x07020002L,0x00000000L,0x2030, 8, 10, 18, 16, 11, 'y', {2,8} , {4,0,0,0} , 5}, {"Red Worm mass" ,0x00200022L,0x00800000L,0x2192, 6, 10, 7, 12, 10, 'w', {5,8} , {111,0,0,0} , 5}, {"Giant House Fly" ,0x00000022L,0x00000000L,0x0062, 10, 20, 12, 16, 13, 'F', {3,8} , {25,0,0,0} , 5}, {"Copperhead Snake" ,0x00000012L,0x00000000L,0x00B2, 15, 1, 6, 20, 11, 'R', {4,6} , {158,0,0,0} , 5}, {"Rot Jelly" ,0x00000001L,0x00000000L,0x10A0, 15, 99, 2, 30, 11, 'J', {20,8} , {209,0,0,0} , 5}, {"Purple Mushroom patch" ,0x00000001L,0x00000000L,0x10A0, 12, 0, 2, 1, 12, ',', {1,1} , {183,0,0,0} , 6}, {"Brown Mold" ,0x00000001L,0x00000000L,0x10A0, 20, 99, 2, 12, 11, 'm', {15,8} , {89,0,0,0} , 6}, {"Giant Brown Bat" ,0x0000001AL,0x00000000L,0x2162, 10, 30, 10, 15, 13, 'b', {3,8} , {26,0,0,0} , 6}, {"Creeping Silver Coins" ,0x16000002L,0x00000000L,0x1000, 18, 10, 4, 30, 10, '$', {12,8} , {5,171,0,0} , 6}, {"Orc" ,0x0B020002L,0x00000000L,0x2034, 16, 30, 20, 32, 11, 'o', {9,8} , {7,0,0,0} , 6}, {"Grey Harpy" ,0x00000012L,0x00000000L,0x2034, 14, 10, 16, 20, 12, 'h', {3,8} , {50,50,25,0} , 6}, {"Blue Icky-Thing" ,0x00000012L,0x00400000L,0x0020, 12, 20, 14, 14, 11, 'i', {4,8} , {126,0,0,0} , 6}, {"Rattlesnake" ,0x00000012L,0x00000000L,0x00B2, 20, 1, 6, 24, 11, 'R', {6,7} , {159,0,0,0} , 6}, {"Bloodshot Eye" ,0x00000001L,0x00010007L,0x2100, 15, 10, 2, 6, 11, 'e', {4,8} , {143,0,0,0} , 7}, {"Red Naga" ,0x0710000AL,0x00000000L,0x20E4, 40, 120, 20, 40, 11, 'n', {11,8} , {76,82,0,0} , 7}, {"Red Jelly" ,0x00000001L,0x00000000L,0x11A0, 26, 99, 2, 1, 11, 'J', {26,8} , {87,0,0,0} , 7}, {"Giant Red Frog" ,0x0000000AL,0x00000000L,0x00A2, 16, 50, 12, 16, 11, 'f', {5,8} , {83,0,0,0} , 7}, {"Green Icky-Thing" ,0x00000012L,0x00000000L,0x0020, 18, 20, 14, 12, 11, 'i', {5,8} , {137,0,0,0} , 7}, {"Zombie Kobold" ,0x00020002L,0x00000000L,0x102C, 14, 30, 20, 14, 11, 'z', {6,8} , {1,1,0,0} , 7}, {"Lost Soul" ,0x0F95001AL,0x0001002FL,0x110C, 18, 10, 12, 10, 11, 'G', {2,8} , {11,185,0,0} , 7}, {"Greedy Little Gnome" ,0x0B920002L,0x00000000L,0x2034, 13, 10, 18, 14, 11, 'p', {3,8} , {6,149,0,0} , 7}, {"Giant Green Fly" ,0x00000022L,0x00000000L,0x0062, 15, 20, 12, 14, 12, 'F', {3,8} , {27,0,0,0} , 7}, {"Brown Yeek" ,0x07020002L,0x00000000L,0x2030, 11, 10, 18, 18, 11, 'y', {3,8} , {5,0,0,0} , 8}, {"Green Mold" ,0x00000001L,0x00000000L,0x10A0, 28, 75, 2, 14, 11, 'm', {21,8} , {94,0,0,0} , 8}, {"Skeleton Orc" ,0x00020002L,0x00000000L,0x100C, 26, 40, 20, 36, 11, 's', {10,8} , {14,0,0,0} , 8}, {"Seedy Looking Human" ,0x13020002L,0x00000000L,0x2034, 22, 20, 20, 26, 11, 'p', {8,8} , {17,0,0,0} , 8}, {"Red Icky-Thing" ,0x00000012L,0x00200000L,0x0020, 22, 20, 14, 18, 12, 'i', {4,8} , {64,117,0,0} , 8}, {"Bandit" ,0x13120002L,0x00000000L,0x2034, 26, 10, 20, 24, 11, 'p', {8,8} , {13,148,0,0} , 8}, {"Yeti" ,0x00020002L,0x00400000L,0x2024, 30, 10, 20, 24, 11, 'Y', {11,8} , {51,51,27,0} , 9}, {"Bloodshot Icky-Thing" ,0x00000012L,0x0001000BL,0x0020, 24, 20, 14, 18, 11, 'i', {7,8} , {65,139,0,0} , 9}, {"Giant Grey Rat" ,0x0020000AL,0x00000000L,0x2072, 2, 20, 8, 12, 11, 'r', {2,3} , {154,0,0,0} , 9}, {"Black Harpy" ,0x0000000AL,0x00000000L,0x2034, 19, 10, 16, 22, 12, 'h', {3,8} , {50,50,26,0} , 9}, {"Giant Black Bat" ,0x00000012L,0x00000000L,0x2162, 16, 25, 12, 18, 13, 'b', {2,8} , {29,0,0,0} , 9}, {"Clear Yeek" ,0x07030002L,0x00000000L,0x0030, 14, 10, 18, 24, 11, 'y', {3,6} , {4,0,0,0} , 9}, {"Orc Shaman" ,0x0B020002L,0x00008085L,0x2034, 30, 20, 20, 15, 11, 'o', {7,8} , {5,0,0,0} , 9}, {"Giant Red Ant" ,0x00000002L,0x00000000L,0x0002, 22, 60, 12, 34, 11, 'a', {4,8} , {27,85,0,0} , 9}, {"King Cobra" ,0x00000012L,0x00000000L,0x00B2, 28, 1, 8, 30, 11, 'R', {8,8} , {144,161,0,0} , 9}, {"Clear Mushroom patch" ,0x00210001L,0x00000000L,0x10A0, 1, 0, 4, 1, 12, ',', {1,1} , {70,0,0,0} , 10}, {"Giant White Tick" ,0x0000000AL,0x00000000L,0x0022, 27, 20, 12, 40, 10, 't', {15,8} , {160,0,0,0} , 10}, {"Hairy Mold" ,0x00000001L,0x00000000L,0x10A0, 32, 70, 2, 15, 11, 'm', {15,8} , {151,0,0,0} , 10}, {"Disenchanter Mold" ,0x00000001L,0x0001000BL,0x10A0, 40, 70, 2, 20, 11, 'm', {16,8} , {206,0,0,0} , 10}, {"Giant Red Centipede" ,0x00000002L,0x00000000L,0x0002, 24, 50, 12, 26, 12, 'c', {3,8} , {25,164,0,0} , 10}, {"Creeping Gold Coins" ,0x1A000002L,0x00000000L,0x1000, 32, 10, 5, 36, 10, '$', {18,8} , {14,172,0,0} , 10}, {"Giant Fruit Fly" ,0x00200022L,0x00000000L,0x0062, 4, 10, 8, 14, 12, 'F', {2,2} , {25,0,0,0} , 10}, {"Brigand" ,0x13120002L,0x00000000L,0x2034, 35, 10, 20, 32, 11, 'p', {9,8} , {13,149,0,0} , 10}, {"Orc Zombie" ,0x00020002L,0x00000000L,0x102C, 30, 25, 20, 24, 11, 'z', {11,8} , {3,3,0,0} , 11}, {"Orc Warrior" ,0x0B020002L,0x00000000L,0x2034, 34, 25, 20, 36, 11, 'o', {11,8} , {15,0,0,0} , 11}, {"Vorpal Bunny" ,0x0020000AL,0x00000000L,0x2072, 2, 30, 8, 10, 12, 'r', {2,3} , {28,0,0,0} , 11}, {"Nasty Little Gnome" ,0x13820002L,0x000020B5L,0x2034, 32, 10, 18, 10, 11, 'p', {4,8} , {4,0,0,0} , 11}, {"Hobgoblin" ,0x0F020002L,0x00000000L,0x2034, 38, 30, 20, 38, 11, 'H', {12,8} , {9,0,0,0} , 11}, {"Black Mamba" ,0x00000012L,0x00000000L,0x00B2, 40, 1, 10, 32, 12, 'R', {10,8} , {163,0,0,0} , 12}, {"Grape Jelly" ,0x00000001L,0x0001000BL,0x11A0, 60, 99, 2, 1, 11, 'J', {52,8} , {186,0,0,0} , 12}, {"Master Yeek" ,0x07020002L,0x00008018L,0x2030, 28, 10, 18, 24, 11, 'y', {5,8} , {7,0,0,0} , 12}, {"Priest" ,0x13020002L,0x00000285L,0x2030, 36, 40, 20, 22, 11, 'p', {7,8} , {12,0,0,0} , 12}, {"Giant Clear Ant" ,0x00010002L,0x00000000L,0x0002, 24, 60, 12, 18, 11, 'a', {3,7} , {27,0,0,0} , 12}, {"Air Spirit" ,0x00030022L,0x00000000L,0x1000, 40, 20, 12, 20, 13, 'E', {5,8} , {2,0,0,0} , 12}, {"Skeleton Human" ,0x00020002L,0x00000000L,0x100C, 38, 30, 20, 30, 11, 's', {12,8} , {7,0,0,0} , 12}, {"Human Zombie" ,0x00020002L,0x00000000L,0x102C, 34, 20, 20, 24, 11, 'z', {11,8} , {3,3,0,0} , 12}, {"Moaning Spirit" ,0x0F15000AL,0x0001002FL,0x110C, 44, 10, 14, 20, 11, 'G', {4,8} , {99,178,0,0} , 12}, {"Swordsman" ,0x13020002L,0x00000000L,0x2030, 40, 20, 20, 34, 11, 'p', {11,8} , {18,0,0,0} , 12}, {"Killer Brown Beetle" ,0x0000000AL,0x00000000L,0x0002, 38, 30, 10, 40, 11, 'K', {13,8} , {41,0,0,0} , 13}, {"Ogre" ,0x07020002L,0x00000000L,0x2034, 42, 30, 20, 32, 11, 'o', {13,8} , {16,0,0,0} , 13}, {"Giant Red Speckled Frog" ,0x0000000AL,0x00000000L,0x00A2, 32, 30, 12, 20, 11, 'f', {6,8} , {41,0,0,0} , 13}, {"Magic User" ,0x13020002L,0x00002413L,0x2030, 35, 10, 20, 10, 11, 'p', {7,8} , {11,0,0,0} , 13}, {"Black Orc" ,0x0B020002L,0x00000000L,0x2034, 40, 20, 20, 36, 11, 'o', {12,8} , {17,0,0,0} , 13}, {"Giant Long-Eared Bat" ,0x00000012L,0x00000000L,0x2162, 20, 20, 12, 20, 13, 'b', {5,8} , {27,50,50,0} , 13}, {"Giant Gnat" ,0x00200022L,0x00000000L,0x0062, 1, 10, 8, 4, 13, 'F', {1,2} , {24,0,0,0} , 13}, {"Killer Green Beetle" ,0x0000000AL,0x00000000L,0x0002, 46, 30, 12, 45, 11, 'K', {16,8} , {43,0,0,0} , 14}, {"Giant Flea" ,0x00200022L,0x00000000L,0x0062, 1, 10, 8, 25, 12, 'F', {2,2} , {25,0,0,0} , 14}, {"Giant White Dragon Fly" ,0x00000012L,0x0040000AL,0x0062, 54, 50, 20, 20, 11, 'F', {5,8} , {122,0,0,0} , 14}, {"Hill Giant" ,0x07020002L,0x00000000L,0x2034, 52, 50, 20, 36, 11, 'P', {16,8} , {19,0,0,0} , 14}, {"Skeleton Hobgoblin" ,0x00020002L,0x00000000L,0x100C, 46, 30, 20, 34, 11, 's', {13,8} , {14,0,0,0} , 14}, {"Flesh Golem" ,0x00000002L,0x00000000L,0x1030, 48, 10, 12, 10, 11, 'g', {12,8} , {5,5,0,0} , 14}, {"White Dragon Bat" ,0x00000012L,0x00400004L,0x0162, 40, 50, 12, 20, 13, 'b', {2,6} , {121,0,0,0} , 14}, {"Giant Black Louse" ,0x00200012L,0x00000000L,0x01F2, 1, 10, 6, 7, 12, 'l', {1,1} , {25,0,0,0} , 14}, {"Guardian Naga" ,0x1710000AL,0x00000000L,0x20E4, 60, 120, 20, 50, 11, 'n', {24,8} , {77,31,0,0} , 15}, {"Giant Grey Bat" ,0x00000012L,0x00000000L,0x2162, 22, 15, 12, 22, 13, 'b', {4,8} , {29,50,50,0} , 15}, {"Giant Clear Centipede" ,0x00010002L,0x00000000L,0x0002, 30, 30, 12, 30, 11, 'c', {5,8} , {34,62,0,0} , 15}, {"Giant Yellow Tick" ,0x0000000AL,0x00000000L,0x0022, 48, 20, 12, 48, 10, 't', {20,8} , {162,0,0,0} , 15}, {"Giant Ebony Ant" ,0x00200002L,0x00000000L,0x0002, 3, 60, 12, 24, 11, 'a', {3,4} , {33,0,0,0} , 15}, {"Frost Giant" ,0x07020002L,0x00400000L,0x0024, 54, 50, 20, 38, 11, 'P', {17,8} , {120,0,0,0} , 15}, {"Clay Golem" ,0x00000002L,0x00000000L,0x1200, 50, 10, 12, 20, 11, 'g', {14,8} , {7,7,0,0} , 15}, {"Huge White Bat" ,0x00200012L,0x00000000L,0x2162, 3, 40, 7, 12, 12, 'b', {3,8} , {29,0,0,0} , 15}, {"Giant Tan Bat" ,0x00000012L,0x00000000L,0x2162, 18, 40, 12, 18, 12, 'b', {3,8} , {95,49,49,0} , 15}, {"Violet Mold" ,0x00000001L,0x00010009L,0x10A0, 50, 70, 2, 15, 11, 'm', {17,8} , {145,0,0,0} , 15}, {"Umber Hulk" ,0x00020002L,0x00000000L,0x2124, 75, 10, 20, 20, 11, 'U', {20,8} , {92,5,5,36} , 16}, {"Gelatinous Cube" ,0x2F98000AL,0x00200000L,0x1020, 36, 1, 12, 18, 10, 'C', {45,8} , {115,0,0,0} , 16}, {"Giant Black Rat" ,0x0020000AL,0x00000000L,0x2072, 3, 20, 8, 16, 11, 'r', {3,4} , {155,0,0,0} , 16}, {"Giant Green Dragon Fly" ,0x00000012L,0x0010000AL,0x0032, 58, 50, 20, 20, 11, 'F', {5,8} , {156,0,0,0} , 16}, {"Fire Giant" ,0x07020002L,0x00800000L,0x2014, 62, 50, 20, 40, 11, 'P', {20,8} , {102,0,0,0} , 16}, {"Green Dragon Bat" ,0x00000012L,0x00100004L,0x2112, 44, 50, 12, 22, 13, 'b', {2,7} , {153,0,0,0} , 16}, {"Quasit" ,0x1183000AL,0x000010FAL,0x1004, 48, 20, 20, 30, 11, 'q', {5,8} , {176,51,51,0} , 16}, {"Troll" ,0x0F020002L,0x00000000L,0x2024, 64, 40, 20, 40, 11, 'T', {17,8} , {3,3,29,0} , 17}, {"Water Spirit" ,0x0000000AL,0x00000000L,0x1020, 58, 40, 12, 28, 12, 'E', {8,8} , {13,0,0,0} , 17}, {"Giant Brown Scorpion" ,0x0000000AL,0x00000000L,0x0002, 62, 20, 12, 44, 11, 'S', {11,8} , {34,86,0,0} , 17}, {"Earth Spirit" ,0x0016000AL,0x00000000L,0x1200, 64, 50, 10, 40, 11, 'E', {13,8} , {7,7,0,0} , 17}, {"Fire Spirit" ,0x0000000AL,0x00800000L,0x3010, 66, 20, 16, 30, 12, 'E', {10,8} , {101,0,0,0} , 18}, {"Uruk-Hai Orc" ,0x0B020002L,0x00000000L,0x2034, 68, 20, 20, 42, 11, 'o', {14,8} , {18,0,0,0} , 18}, {"Stone Giant" ,0x07020002L,0x00000000L,0x2204, 80, 50, 20, 40, 11, 'P', {22,8} , {20,0,0,0} , 18}, {"Stone Golem" ,0x00000002L,0x00000000L,0x1200, 100, 10, 12, 75, 10, 'g', {28,8} , {9,9,0,0} , 19}, {"Grey Ooze" ,0x07980022L,0x00400000L,0x10A0, 40, 1, 15, 10, 11, 'O', {6,8} , {127,0,0,0} , 19}, {"Disenchanter Ooze" ,0x07980022L,0x00000000L,0x10B0, 50, 1, 15, 15, 11, 'O', {6,8} , {205,0,0,0} , 19}, {"Giant Spotted Rat" ,0x0020000AL,0x00000000L,0x2072, 3, 20, 8, 20, 11, 'r', {4,3} , {155,0,0,0} , 19}, {"Mummified Kobold" ,0x0B820002L,0x00000000L,0x102C, 46, 75, 20, 24, 11, 'M', {13,8} , {5,5,0,0} , 19}, {"Killer Black Beetle" ,0x0000000AL,0x00000000L,0x0002, 75, 30, 12, 46, 11, 'K', {18,8} , {44,0,0,0} , 19}, {"Red Mold" ,0x00000001L,0x00800000L,0x3090, 64, 70, 2, 16, 11, 'm', {17,8} , {108,0,0,0} , 19}, {"Quylthulg" ,0x00010004L,0x00002017L,0x5000, 200, 0, 10, 1, 11, 'Q', {4,8} , {0,0,0,0} , 20}, {"Giant Red Bat" ,0x00000012L,0x00000000L,0x2162, 40, 20, 12, 24, 12, 'b', {5,8} , {30,51,51,0} , 20}, {"Giant Black Dragon Fly" ,0x00000012L,0x00200009L,0x0072, 58, 50, 20, 22, 11, 'F', {4,8} , {141,0,0,0} , 20}, {"Cloud Giant" ,0x07020002L,0x00080000L,0x2034, 125, 50, 20, 44, 11, 'P', {24,8} , {130,0,0,0} , 20}, {"Black Dragon Bat" ,0x00000012L,0x00200004L,0x2152, 50, 50, 12, 24, 13, 'b', {2,8} , {112,0,0,0} , 21}, {"Blue Dragon Bat" ,0x00000012L,0x00080004L,0x2052, 54, 50, 12, 26, 13, 'b', {3,6} , {131,0,0,0} , 21}, {"Mummified Orc" ,0x0B020002L,0x00000000L,0x102C, 56, 75, 20, 28, 11, 'M', {14,8} , {13,13,0,0} , 21}, {"Killer Boring Beetle" ,0x0000000AL,0x00000000L,0x0002, 70, 30, 12, 48, 11, 'K', {18,8} , {44,0,0,0} , 21}, {"Killer Stag Beetle" ,0x0000000AL,0x00000000L,0x0002, 80, 30, 12, 50, 11, 'K', {20,8} , {41,10,0,0} , 22}, {"Black Mold" ,0x00000081L,0x00000000L,0x10A0, 68, 50, 2, 18, 11, 'm', {15,8} , {21,0,0,0} , 22}, {"Iron Golem" ,0x00000002L,0x00000000L,0x1080, 160, 10, 12, 99, 9, 'g', {80,8} , {10,10,0,0} , 22}, {"Giant Yellow Scorpion" ,0x0000000AL,0x00000000L,0x0002, 60, 20, 12, 38, 11, 'S', {12,8} , {31,167,0,0} , 22}, {"Green Ooze" ,0x07BA0012L,0x00200000L,0x1030, 6, 1, 15, 5, 10, 'O', {4,8} , {116,0,0,0} , 22}, {"Black Ooze" ,0x07BA0012L,0x0001000BL,0x1030, 7, 1, 10, 6, 9, 'O', {6,8} , {138,0,0,0} , 23}, {"Warrior" ,0x13020002L,0x00000000L,0x2030, 60, 40, 20, 40, 11, 'p', {15,8} , {18,0,0,0} , 23}, {"Red Dragon Bat" ,0x00000012L,0x00800004L,0x2152, 60, 50, 12, 28, 13, 'b', {3,8} , {105,0,0,0} , 23}, {"Killer Blue Beetle" ,0x0000000AL,0x00000000L,0x0002, 85, 30, 14, 50, 11, 'K', {20,8} , {44,0,0,0} , 23}, {"Giant Silver Ant" ,0x0000000AL,0x00200000L,0x0002, 45, 60, 10, 38, 11, 'a', {6,8} , {114,0,0,0} , 23}, {"Crimson Mold" ,0x00000001L,0x00000000L,0x10A0, 65, 50, 2, 18, 11, 'm', {16,8} , {2,97,0,0} , 23}, {"Forest Wight" ,0x0F02000AL,0x0000100FL,0x112C, 140, 30, 20, 30, 11, 'W', {12,8} , {5,5,187,0} , 24}, {"Berzerker" ,0x13020002L,0x00000000L,0x2030, 65, 10, 20, 20, 11, 'p', {15,8} , {7,7,0,0} , 24}, {"Mummified Human" ,0x0B020002L,0x00000000L,0x102C, 70, 60, 20, 34, 11, 'M', {17,8} , {13,13,0,0} , 24}, {"Banshee" ,0x0F15001AL,0x0001002FL,0x110C, 60, 10, 20, 24, 12, 'G', {6,8} , {99,188,0,0} , 24}, {"Giant Troll" ,0x0F020002L,0x00000000L,0x2024, 85, 50, 20, 40, 11, 'T', {19,8} , {5,5,41,0} , 25}, {"Giant Brown Tick" ,0x0000000AL,0x00000000L,0x0022, 70, 20, 12, 50, 10, 't', {18,8} , {157,142,0,0} , 25}, {"Killer Red Beetle" ,0x0000000AL,0x00000000L,0x0002, 85, 30, 14, 50, 11, 'K', {20,8} , {84,0,0,0} , 25}, {"Wooden Mold" ,0x00000001L,0x00000000L,0x10A0, 100, 50, 2, 50, 11, 'm', {25,8} , {171,0,0,0} , 25}, {"Giant Blue Dragon Fly" ,0x00000012L,0x00080009L,0x0072, 75, 50, 20, 24, 11, 'F', {6,8} , {29,0,0,0} , 25}, {"Giant Grey Ant Lion" ,0x0008000AL,0x00000000L,0x0032, 90, 40, 10, 40, 11, 'A', {19,8} , {39,0,0,0} , 26}, {"Disenchanter Bat" ,0x00000012L,0x00000000L,0x2162, 75, 1, 14, 24, 13, 'b', {4,8} , {204,0,0,0} , 26}, {"Giant Fire Tick" ,0x0000000AL,0x00800000L,0x2012, 90, 20, 14, 54, 11, 't', {16,8} , {109,0,0,0} , 26}, {"White Wraith" ,0x0F02000AL,0x0000100CL,0x112C, 165, 10, 20, 40, 11, 'W', {15,8} , {5,5,189,0} , 26}, {"Giant Black Scorpion" ,0x0000000AL,0x00000000L,0x0002, 85, 20, 12, 50, 11, 'S', {13,8} , {32,167,0,0} , 26}, {"Clear Ooze" ,0x0799000AL,0x00000000L,0x10B0, 12, 1, 10, 14, 11, 'O', {4,8} , {90,0,0,0} , 26}, {"Killer Fire Beetle" ,0x0000000AL,0x00800000L,0x2012, 95, 30, 14, 45, 11, 'K', {13,8} , {41,110,0,0} , 27}, {"Vampire" ,0x17020002L,0x00001209L,0x112C, 175, 10, 20, 45, 11, 'V', {20,8} , {5,5,190,0} , 27}, {"Giant Red Dragon Fly" ,0x00000012L,0x00800008L,0x2052, 75, 50, 20, 24, 11, 'F', {7,8} , {96,0,0,0} , 27}, {"Shimmering Mold" ,0x00000081L,0x00080000L,0x10A0, 180, 50, 2, 24, 11, 'm', {32,8} , {135,0,0,0} , 27}, {"Black Knight" ,0x13020002L,0x0000010FL,0x2034, 140, 10, 20, 60, 11, 'p', {25,8} , {23,0,0,0} , 28}, {"Mage" ,0x13020002L,0x00002C73L,0x2030, 150, 10, 20, 30, 11, 'p', {10,8} , {14,0,0,0} , 28}, {"Ice Troll" ,0x0F020002L,0x00400000L,0x0024, 160, 50, 20, 46, 11, 'T', {22,8} , {4,4,123,0} , 28}, {"Giant Purple Worm" ,0x0000000AL,0x00200000L,0x2032, 400, 30, 14, 65, 11, 'w', {65,8} , {7,113,166,0} , 29}, {"Young Blue Dragon" ,0x1F00000AL,0x0008100BL,0x2005, 300, 70, 20, 50, 11, 'd', {33,8} , {52,52,29,0} , 29}, {"Young White Dragon" ,0x1F00000AL,0x0040100BL,0x0025, 275, 70, 20, 50, 11, 'd', {32,8} , {52,52,29,0} , 29}, {"Young Green Dragon" ,0x1F00000AL,0x0010100BL,0x2005, 290, 70, 20, 50, 11, 'd', {32,8} , {52,52,29,0} , 29}, {"Giant Fire Bat" ,0x00000012L,0x00800000L,0x2152, 85, 10, 14, 30, 12, 'b', {5,8} , {106,52,52,0} , 29}, {"Giant Glowing Rat" ,0x0020000AL,0x00080000L,0x2072, 4, 20, 8, 24, 11, 'r', {3,3} , {132,0,0,0} , 29}, /* Now things are going to get tough. */ /* Some of the creatures have Max hit points, denoted in */ /* their CDEFENSE flags as the '4000' bit set */ {"Skeleton Troll" ,0x00020002L,0x00000000L,0x500C, 225, 20, 20, 55, 11, 's', {14,8} , {5,5,41,0} , 30}, {"Giant Lightning Bat" ,0x00000012L,0x00080000L,0x2042, 80, 10, 15, 34, 12, 'b', {8,8} , {133,53,53,0} , 30}, {"Giant Static Ant" ,0x0000000AL,0x00080000L,0x0002, 80, 60, 10, 40, 11, 'a', {8,8} , {134,0,0,0} , 30}, {"Grave Wight" ,0x0F02000AL,0x0000110AL,0x512C, 325, 30, 20, 35, 11, 'W', {12,8} , {6,6,191,0} , 30}, {"Killer Slicer Beetle" ,0x0000000AL,0x00000000L,0x0002, 200, 30, 14, 55, 11, 'K', {22,8} , {48,0,0,0} , 30}, {"Giant White Ant Lion" ,0x0008000AL,0x00400000L,0x0022, 175, 40, 12, 45, 11, 'A', {20,8} , {124,0,0,0} , 30}, {"Ghost" ,0x1715000AL,0x0001002FL,0x510C, 350, 10, 20, 30, 12, 'G', {13,8} , {99,192,184,0} , 31}, {"Giant Black Ant Lion" ,0x0008000AL,0x00200000L,0x0032, 170, 40, 14, 45, 11, 'A', {23,8} , {39,119,0,0} , 31}, {"Death Watch Beetle" ,0x0000000AL,0x00000000L,0x0002, 190, 30, 16, 60, 11, 'K', {25,8} , {47,67,0,0} , 31}, {"Ogre Mage" ,0x0B020002L,0x0000A355L,0x6034, 250, 30, 20, 42, 11, 'o', {14,8} , {19,0,0,0} , 31}, {"Two-Headed Troll" ,0x0F020002L,0x00000000L,0x6024, 275, 50, 20, 48, 11, 'T', {14,8} , {7,7,29,29} , 32}, {"Invisible Stalker" ,0x00030022L,0x00000000L,0x1000, 200, 20, 20, 46, 13, 'E', {19,8} , {5,0,0,0} , 32}, {"Giant Hunter Ant" ,0x00000002L,0x00000000L,0x0002, 150, 1, 16, 40, 11, 'a', {12,8} , {46,0,0,0} , 32}, {"Ninja" ,0x13020002L,0x00000000L,0x6034, 300, 10, 20, 65, 11, 'p', {15,8} , {152,80,0,0} , 32}, {"Barrow Wight" ,0x0F02000AL,0x00001308L,0x512C, 375, 10, 20, 40, 11, 'W', {13,8} , {7,7,193,0} , 33}, {"Skeleton 2-Headed Troll" ,0x00020002L,0x00000000L,0x500C, 325, 20, 20, 48, 11, 's', {20,8} , {8,8,28,28} , 33}, {"Water Elemental" ,0x0008000AL,0x00000000L,0x1020, 325, 50, 12, 36, 11, 'E', {25,8} , {9,9,0,0} , 33}, {"Fire Elemental" ,0x0008000AL,0x00800000L,0x3010, 350, 70, 16, 40, 10, 'E', {25,8} , {103,0,0,0} , 33}, {"Lich" ,0x1F020002L,0x00019F75L,0x510C, 750, 60, 20, 50, 11, 'L', {25,8} , {179,194,214,0} , 34}, {"Master Vampire" ,0x17020002L,0x00001307L,0x512C, 700, 10, 20, 55, 11, 'V', {23,8} , {5,5,195,0} , 34}, {"Spirit Troll" ,0x17150002L,0x00000000L,0x510C, 425, 10, 20, 40, 11, 'G', {15,8} , {53,53,29,185} , 34}, {"Giant Red Scorpion" ,0x0000000AL,0x00000000L,0x0002, 275, 40, 12, 50, 12, 'S', {18,8} , {29,165,0,0} , 34}, {"Earth Elemental" ,0x001E000AL,0x00000000L,0x1200, 375, 90, 10, 60, 10, 'E', {30,8} , {22,22,0,0} , 34}, {"Young Black Dragon" ,0x1F00000AL,0x0020100BL,0x6005, 600, 50, 20, 55, 11, 'd', {32,8} , {53,53,29,0} , 35}, {"Young Red Dragon" ,0x1F00000AL,0x0080100AL,0x6015, 650, 50, 20, 60, 11, 'd', {36,8} , {54,54,37,0} , 35}, {"Necromancer" ,0x13020002L,0x00005763L,0x6030, 600, 10, 20, 40, 11, 'p', {17,8} , {15,0,0,0} , 35}, {"Mummified Troll" ,0x0F020002L,0x00000000L,0x502C, 400, 50, 20, 38, 11, 'M', {18,8} , {15,15,0,0} , 35}, {"Giant Red Ant Lion" ,0x0008000AL,0x00800000L,0x2012, 350, 40, 14, 48, 11, 'A', {23,8} , {107,0,0,0} , 35}, {"Mature White Dragon" ,0x2F00000AL,0x0040100AL,0x4025, 1000, 70, 20, 65, 11, 'd', {48,8} , {54,54,37,0} , 35}, {"Xorn" ,0x00160002L,0x00000000L,0x4200, 650, 10, 20, 80, 11, 'X', {20,8} , {5,5,5,0} , 36}, {"Giant Mottled Ant Lion" ,0x0008000AL,0x00000000L,0x0032, 350, 40, 14, 50, 12, 'A', {24,8} , {38,0,0,0} , 36}, {"Grey Wraith" ,0x0F02000AL,0x00001308L,0x512C, 700, 10, 20, 50, 11, 'W', {23,8} , {9,9,196,0} , 36}, {"Young Multi-Hued Dragon" ,0x4F00000AL,0x00F81005L,0x6005, 1250, 50, 20, 55, 11, 'd', {40,8} , {55,55,38,0} , 36}, {"Mature Blue Dragon" ,0x2F00000AL,0x00081009L,0x6005, 1200, 70, 20, 75, 11, 'd', {48,8} , {54,54,38,0} , 36}, {"Mature Green Dragon" ,0x2F00000AL,0x0010100AL,0x6005, 1100, 70, 20, 70, 11, 'd', {48,8} , {52,52,29,0} , 36}, {"Iridescent Beetle" ,0x0000000AL,0x00000000L,0x0002, 850, 30, 16, 60, 11, 'K', {32,8} , {45,10,146,0} , 37}, {"King Vampire" ,0x17020002L,0x00001307L,0x512C, 1000, 10, 20, 65, 11, 'V', {38,8} , {5,5,198,0} , 37}, {"King Lich" ,0x1F020002L,0x00019F73L,0x510C, 1400, 50, 20, 65, 11, 'L', {52,8} , {180,197,214,0} , 37}, {"Mature Red Dragon" ,0x2F00000AL,0x00801808L,0x6015, 1400, 30, 20, 80, 11, 'd', {60,8} , {56,56,39,0} , 37}, {"Mature Black Dragon" ,0x2F00000AL,0x00201009L,0x6005, 1350, 30, 20, 55, 11, 'd', {58,8} , {54,54,38,0} , 37}, {"Mature Multi-Hued Dragon" ,0x6F00000AL,0x00F81A05L,0x6005, 1650, 50, 20, 65, 11, 'd', {80,8} , {56,56,39,0} , 38}, {"Ancient White Dragon" ,0x4F000002L,0x00401A09L,0x4025, 1500, 80, 20, 80, 12, 'D', {88,8} , {54,54,37,0} , 38}, {"Emperor Wight" ,0x1B02000AL,0x00001306L,0x512C, 1600, 10, 20, 40, 12, 'W', {48,8} , {10,10,199,0} , 38}, {"Black Wraith" ,0x1F02000AL,0x00001307L,0x512C, 1700, 10, 20, 55, 11, 'W', {50,8} , {10,10,200,0} , 38}, {"Nether Wraith" ,0x1F07000AL,0x00005316L,0x512C, 2100, 10, 20, 55, 11, 'W', {58,8} , {10,10,202,0} , 39}, {"Sorcerer" ,0x1F020002L,0x0000FF73L,0x6030, 2150, 10, 20, 50, 12, 'p', {30,8} , {16,0,0,0} , 39}, {"Ancient Blue Dragon" ,0x4F000002L,0x00081A08L,0x6005, 2500, 80, 20, 90, 12, 'D', {87,8} , {55,55,39,0} , 39}, {"Ancient Green Dragon" ,0x4F000002L,0x00101A09L,0x6005, 2400, 80, 20, 85, 12, 'D', {90,8} , {54,54,38,0} , 39}, {"Ancient Black Dragon" ,0x4F000002L,0x00201A07L,0x6005, 2500, 70, 20, 90, 12, 'D', {90,8} , {55,55,38,0} , 39}, {"Crystal Ooze" ,0x07BB000AL,0x00400000L,0x10A0, 8, 1, 10, 30, 9, 'O', {12,8} , {128,0,0,0} , 40}, {"Disenchanter Worm" ,0x00200022L,0x00000000L,0x01B2, 30, 10, 7, 5, 10, 'w', {10,8} , {208,0,0,0} , 40}, {"Rotting Quylthulg" ,0x00010004L,0x00004014L,0x5000, 1000, 0, 20, 1, 12, 'Q', {12,8} , {0,0,0,0} , 40}, {"Ancient Red Dragon" ,0x6F000002L,0x00801E06L,0x6015, 2750, 70, 20, 100, 12, 'D', {105,8} , {56,56,40,0} , 40}, {"Death Quasit" ,0x1103000AL,0x000010FAL,0x1004, 1000, 0, 20, 80, 13, 'q', {55,8} , {177,58,58,0} , 40}, {"Emperor Lich" ,0x2F020002L,0x00019F72L,0x510C,10000, 50, 20, 75, 12, 'L', {38,40} , {181,201,214,0} , 40}, {"Ancient Multi-Hued Dragon",0x7F000002L,0x00F89E05L,0x6005,12000, 70, 20, 100, 12, 'D', {52,40} , {57,57,42,0} , 40}, /* Winning creatures should follow here. */ /* Winning creatures are denoted by the 32 bit in CMOVE */ /* Iggy is not a win creature, just a royal pain in the ass. */ {"Evil Iggy" ,0x7F130002L,0x0001D713L,0x5004,18000, 0, 30, 80, 12, 'p', {60,40} , {81,150,0,0} , 50}, /* Here is the only actual win creature. */ {"Balrog" ,0xFF1F0002L,0x0081C743L,0x5004,55000L, 0, 40, 125, 13, 'B', {75,40} , {104,78,214,0} , 100} }; #endif /* ERROR: attack #35 is no longer used */ struct m_attack_type monster_attacks[N_MONS_ATTS] = { /* 0 */ {0, 0, 0, 0}, {1, 1, 1, 2}, {1, 1, 1, 3}, {1, 1, 1, 4}, {1, 1, 1, 5}, {1, 1, 1, 6}, {1, 1, 1, 7}, {1, 1, 1, 8}, {1, 1, 1, 9}, {1, 1, 1, 10}, {1, 1, 1, 12}, {1, 1, 2, 2}, {1, 1, 2, 3}, {1, 1, 2, 4}, {1, 1, 2, 5}, {1, 1, 2, 6}, {1, 1, 2, 8}, {1, 1, 3, 4}, {1, 1, 3, 5}, {1, 1, 3, 6}, /* 20 */{1, 1, 3, 8}, {1, 1, 4, 3}, {1, 1, 4, 6}, {1, 1, 5, 5}, {1, 2, 1, 1}, {1, 2, 1, 2}, {1, 2, 1, 3}, {1, 2, 1, 4}, {1, 2, 1, 5}, {1, 2, 1, 6}, {1, 2, 1, 7}, {1, 2, 1, 8}, {1, 2, 1, 10}, {1, 2, 2, 3}, {1, 2, 2, 4}, {1, 2, 2, 5}, {1, 2, 2, 6}, {1, 2, 2, 8}, {1, 2, 2, 10}, {1, 2, 2, 12}, /* 40 */{1, 2, 2, 14}, {1, 2, 3, 4}, {1, 2, 3, 12}, {1, 2, 4, 4}, {1, 2, 4, 5}, {1, 2, 4, 6}, {1, 2, 4, 8}, {1, 2, 5, 4}, {1, 2, 5, 8}, {1, 3, 1, 1}, {1, 3, 1, 2}, {1, 3, 1, 3}, {1, 3, 1, 4}, {1, 3, 1, 5}, {1, 3, 1, 8}, {1, 3, 1, 9}, {1, 3, 1, 10}, {1, 3, 1, 12}, {1, 3, 3, 3}, {1, 4, 1, 2}, /* 60 */{1, 4, 1, 3}, {1, 4, 1, 4}, {1, 4, 2, 4}, {1, 5, 1, 2}, {1, 5, 1, 3}, {1, 5, 1, 4}, {1, 5, 1, 5}, {1, 10, 5, 6}, {1, 12, 1, 1}, {1, 12, 1, 2}, {1, 13, 1, 1}, {1, 13, 1, 3}, {1, 14, 0, 0}, {1, 16, 1, 4}, {1, 16, 1, 6}, {1, 16, 1, 8}, {1, 16, 1, 10}, {1, 16, 2, 8}, {1, 17, 8, 12}, {1, 18, 0, 0}, /* 80 */{2, 1, 3, 4}, {2, 1, 4, 6}, {2, 2, 1, 4}, {2, 2, 2, 4}, {2, 2, 4, 4}, {2, 4, 1, 4}, {2, 4, 1, 7}, {2, 5, 1, 5}, {2, 7, 1, 6}, {3, 1, 1, 4}, {3, 5, 1, 8}, {3, 13, 1, 4}, {3, 7, 0, 0}, {4, 1, 1, 1}, {4, 1, 1, 4}, {4, 2, 1, 2}, {4, 2, 1, 6}, {4, 5, 0, 0}, {4, 7, 0, 0}, {4, 10, 0, 0}, /*100 */{4, 13, 1, 6}, {5, 1, 2, 6}, {5, 1, 3, 7}, {5, 1, 4, 6}, {5, 1, 10, 12}, {5, 2, 1, 3}, {5, 2, 3, 6}, {5, 2, 3, 12}, {5, 5, 4, 4}, {5, 9, 3, 7}, {5, 9, 4, 5}, {5, 12, 1, 6}, {6, 2, 1, 3}, {6, 2, 2, 8}, {6, 2, 4, 4}, {6, 5, 1, 10}, {6, 5, 2, 3}, {6, 8, 1, 5}, {6, 9, 2, 6}, {6, 9, 3, 6}, /*120 */{7, 1, 3, 6}, {7, 2, 1, 3}, {7, 2, 1, 6}, {7, 2, 3, 6}, {7, 2, 3, 10}, {7, 5, 1, 6}, {7, 5, 2, 3}, {7, 5, 2, 6}, {7, 5, 4, 4}, {7, 12, 1, 4}, {8, 1, 3, 8}, {8, 2, 1, 3}, {8, 2, 2, 6}, {8, 2, 3, 8}, {8, 2, 5, 5}, {8, 5, 5, 4}, {9, 5, 1, 2}, {9, 5, 2, 5}, {9, 5, 2, 6}, {9, 8, 2, 4}, /*140 */{9, 12, 1, 3}, {10, 2, 1, 6}, {10, 4, 1, 1}, {10, 7, 2, 6}, {10, 9, 1, 2}, {11, 1, 1, 2}, {11, 7, 0, 0}, {11, 13, 2, 4}, {12, 5, 0, 0}, {13, 5, 0, 0}, {13, 19, 0, 0}, {14, 1, 1, 3}, {14, 1, 3, 4}, {14, 2, 1, 3}, {14, 2, 1, 4}, {14, 2, 1, 5}, {14, 2, 1, 6}, {14, 2, 1, 10}, {14, 2, 2, 4}, {14, 2, 2, 5}, /*160 */{14, 2, 2, 6}, {14, 2, 3, 4}, {14, 2, 3, 9}, {14, 2, 4, 4}, {14, 4, 1, 2}, {14, 4, 1, 4}, {14, 4, 1, 8}, {14, 4, 2, 5}, {14, 5, 1, 2}, {14, 5, 1, 3}, {14, 5, 2, 4}, {14, 5, 2, 6}, {14, 5, 3, 5}, {14, 12, 1, 2}, {14, 12, 1, 4}, {14, 13, 2, 4}, {15, 2, 1, 6}, {15, 2, 3, 6}, {15, 5, 1, 8}, {15, 5, 2, 8}, /*180 */{15, 5, 2, 10}, {15, 5, 2, 12}, {15, 12, 1, 3}, {16, 13, 1, 2}, {17, 3, 1, 10}, {18, 5, 0, 0}, {19, 5, 5, 8}, {19, 5, 12, 8}, {19, 5, 14, 8}, {19, 5, 15, 8}, {19, 5, 18, 8}, {19, 5, 20, 8}, {19, 5, 22, 8}, {19, 5, 26, 8}, {19, 5, 30, 8}, {19, 5, 32, 8}, {19, 5, 34, 8}, {19, 5, 36, 8}, {19, 5, 38, 8}, {19, 5, 42, 8}, /*200 */{19, 5, 44, 8}, {19, 5, 46, 8}, {19, 5, 52, 8}, {20, 10, 0, 0}, {21, 1, 0, 0}, {21, 5, 0, 0}, {21, 5, 1, 6}, {21, 7, 0, 0}, {21, 12, 1, 4}, {22, 5, 2, 3}, {22, 12, 0, 0}, {22, 15, 1, 1}, /*212 */{23, 1, 1, 1}, {23, 5, 1, 3}, {24, 5, 0, 0} }; monster_type m_list[MAX_MALLOC]; int16 m_level[MAX_MONS_LEVEL+1]; /* Blank monster values */ monster_type blank_monster = {0,0,0,0,0,0,0,FALSE,0,FALSE}; int16 mfptr; /* Cur free monster ptr */ int16 mon_tot_mult; /* # of repro's of creature */ moria-5.6.debian.1/source/externs.h0000644000175000017500000007200311074756544015343 0ustar pjbpjb/* source/externs.h: declarations for global variables and initialized data Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include /* VMS requires that this be in externs.h, not files.c; this prevents a 'psect' error for the variable errno */ #include /* Atari TC requires prototypes, but does not have __STDC__. Hence, we check for ATARIST_TC here, and define LINT_ARGS if true. */ #ifdef ATARIST_TC #define LINT_ARGS #endif /* This causes more trouble than it is worth, and very few systems still have this bug in their include files. */ #if 0 /* many systems don't define these anywhere */ #ifndef NeXT #ifndef AMIGA #if !defined(atarist) || !defined(__GNUC__) #ifndef __TURBOC__ #if defined(USG) || defined(DGUX) extern int sprintf(); #else extern char *sprintf(); #endif #endif #endif #endif #endif #endif /* to avoid 'psect' problem with VMS declaration of errno */ #ifndef VMS extern int errno; #endif extern char *copyright[5]; /* horrible hack: needed because compact_monster() can be called from deep within creatures() via place_monster() and summon_monster() */ extern int hack_monptr; extern vtype died_from; extern vtype savefile; /* The save file. -CJS- */ extern int32 birth_date; /* These are options, set with set_options command -CJS- */ extern int rogue_like_commands; extern int find_cut; /* Cut corners on a run */ extern int find_examine; /* Check corners on a run */ extern int find_prself; /* Print yourself on a run (slower) */ extern int find_bound; /* Stop run when the map shifts */ extern int prompt_carry_flag; /* Prompt to pick something up */ extern int show_weight_flag; /* Display weights in inventory */ extern int highlight_seams; /* Highlight magma and quartz */ extern int find_ignore_doors; /* Run through open doors */ extern int sound_beep_flag; /* Beep for invalid character */ extern int display_counts; /* Display rest/repeat counts */ /* global flags */ extern int new_level_flag; /* Next level when true */ extern int teleport_flag; /* Handle teleport traps */ extern int eof_flag; /* Used to handle eof/HANGUP */ extern int player_light; /* Player carrying light */ extern int find_flag; /* Used in MORIA */ extern int free_turn_flag; /* Used in MORIA */ extern int weapon_heavy; /* Flag if the weapon too heavy -CJS- */ extern int pack_heavy; /* Flag if the pack too heavy -CJS- */ extern char doing_inven; /* Track inventory commands */ extern int screen_change; /* Screen changes (used in inven_commands) */ extern int character_generated; /* don't save score until char gen finished*/ extern int character_saved; /* prevents save on kill after save_char() */ extern FILE *highscore_fp; /* High score file pointer */ extern int command_count; /* Repetition of commands. -CJS- */ extern int default_dir; /* Use last direction in repeated commands */ extern int16 noscore; /* Don't score this game. -CJS- */ extern int32u randes_seed; /* For encoding colors */ extern int32u town_seed; /* Seed for town genera*/ extern int16 dun_level; /* Cur dungeon level */ extern int16 missile_ctr; /* Counter for missiles */ extern int msg_flag; /* Set with first msg */ extern vtype old_msg[MAX_SAVE_MSG]; /* Last messages -CJS- */ extern int16 last_msg; /* Where in the array is the last */ extern int death; /* True if died */ extern int32 turn; /* Cur trun of game */ extern int wizard; /* Wizard flag */ extern int to_be_wizard; extern int16 panic_save; /* this is true if playing from a panic save */ extern int wait_for_more; extern char days[7][29]; extern int closing_flag; /* Used for closing */ extern int16 cur_height, cur_width; /* Cur dungeon size */ /* Following are calculated from max dungeon sizes */ extern int16 max_panel_rows, max_panel_cols; extern int panel_row, panel_col; extern int panel_row_min, panel_row_max; extern int panel_col_min, panel_col_max; extern int panel_col_prt, panel_row_prt; /* Following are all floor definitions */ #ifdef MAC extern cave_type (*cave)[MAX_WIDTH]; #else extern cave_type cave[MAX_HEIGHT][MAX_WIDTH]; #endif /* Following are player variables */ extern player_type py; #ifdef MACGAME extern char *(*player_title)[MAX_PLAYER_LEVEL]; extern race_type *race; extern background_type *background; #else extern char *player_title[MAX_CLASS][MAX_PLAYER_LEVEL]; extern race_type race[MAX_RACES]; extern background_type background[MAX_BACKGROUND]; #endif extern int32u player_exp[MAX_PLAYER_LEVEL]; extern int16u player_hp[MAX_PLAYER_LEVEL]; extern int16 char_row; extern int16 char_col; extern int8u rgold_adj[MAX_RACES][MAX_RACES]; extern class_type class[MAX_CLASS]; extern int16 class_level_adj[MAX_CLASS][MAX_LEV_ADJ]; /* Warriors don't have spells, so there is no entry for them. */ #ifdef MACGAME extern spell_type (*magic_spell)[31]; #else extern spell_type magic_spell[MAX_CLASS-1][31]; #endif extern char *spell_names[62]; extern int32u spell_learned; /* Bit field for spells learnt -CJS- */ extern int32u spell_worked; /* Bit field for spells tried -CJS- */ extern int32u spell_forgotten; /* Bit field for spells forgotten -JEW- */ extern int8u spell_order[32]; /* remember order that spells are learned in */ extern int16u player_init[MAX_CLASS][5]; extern int16 total_winner; extern int32 max_score; /* Following are store definitions */ #ifdef MACGAME extern owner_type *owners; #else extern owner_type owners[MAX_OWNERS]; #endif #ifdef MAC extern store_type *store; #else extern store_type store[MAX_STORES]; #endif extern int16u store_choice[MAX_STORES][STORE_CHOICES]; #ifndef MAC extern int (*store_buy[MAX_STORES])(); #endif /* Following are treasure arrays and variables */ #ifdef MACGAME extern treasure_type *object_list; #else extern treasure_type object_list[MAX_OBJECTS]; #endif extern int8u object_ident[OBJECT_IDENT_SIZE]; extern int16 t_level[MAX_OBJ_LEVEL+1]; extern inven_type t_list[MAX_TALLOC]; extern inven_type inventory[INVEN_ARRAY_SIZE]; extern char *special_names[SN_ARRAY_SIZE]; extern int16 sorted_objects[MAX_DUNGEON_OBJ]; extern int16 inven_ctr; /* Total different obj's */ extern int16 inven_weight; /* Cur carried weight */ extern int16 equip_ctr; /* Cur equipment ctr */ extern int16 tcptr; /* Cur treasure heap ptr */ /* Following are creature arrays and variables */ #ifdef MACGAME extern creature_type *c_list; #else extern creature_type c_list[MAX_CREATURES]; #endif extern monster_type m_list[MAX_MALLOC]; extern int16 m_level[MAX_MONS_LEVEL+1]; extern m_attack_type monster_attacks[N_MONS_ATTS]; #ifdef MAC extern recall_type *c_recall; #else extern recall_type c_recall[MAX_CREATURES]; /* Monster memories. -CJS- */ #endif extern monster_type blank_monster; /* Blank monster values */ extern int16 mfptr; /* Cur free monster ptr */ extern int16 mon_tot_mult; /* # of repro's of creature */ /* Following are arrays for descriptive pieces */ #ifdef MACGAME extern char **colors; extern char **mushrooms; extern char **woods; extern char **metals; extern char **rocks; extern char **amulets; extern char **syllables; #else extern char *colors[MAX_COLORS]; extern char *mushrooms[MAX_MUSH]; extern char *woods[MAX_WOODS]; extern char *metals[MAX_METALS]; extern char *rocks[MAX_ROCKS]; extern char *amulets[MAX_AMULETS]; extern char *syllables[MAX_SYLLABLES]; #endif extern int8u blows_table[7][6]; extern int16u normal_table[NORMAL_TABLE_SIZE]; /* Initialized data which had to be moved from some other file */ /* Since these get modified, macrsrc.c must be able to access them */ /* Otherwise, game cannot be made restartable */ /* dungeon.c */ extern char last_command; /* Memory of previous command. */ /* moria1.c */ /* Track if temporary light about player. */ extern int light_flag; #ifdef MSDOS extern int8u floorsym, wallsym; extern int ansi, saveprompt; extern char moriatop[], moriasav[]; #endif /* function return values */ /* only extern functions declared here, static functions declared inside the file that defines them */ #if defined(LINT_ARGS) /* these prototypes can be used by MSC and TC for type checking of arguments WARNING: note that this does not work for all ANSI C compilers, e.g. Gnu C, will give error messages if you use these prototypes. This is due to differing interpretations of the ANSI C standard, specifically how to handle promotion of parameters. In my reading of the standard, I believe that Gnu C's behaviour is correct. */ #ifdef ATARI_ST /* atarist.c */ int check_input(int microsec); void user_name(char * buf); int access(char * name, int dum); void chmod(char * name, int mode); /* dummy function */ #endif /* create.c */ void create_character(void); /* creature.c */ void update_mon(int); int multiply_monster(int, int, int, int); void creatures(int); /* death.c */ void display_scores(int); int duplicate_character(void); int32 total_points(void); void exit_game(void); /* desc.c */ int is_a_vowel(char); void magic_init(void); int16 object_offset(struct inven_type *); void known1(struct inven_type *); int known1_p(struct inven_type *); void known2(struct inven_type *); int known2_p(struct inven_type *); void clear_known2(struct inven_type *); void clear_empty(inven_type *); void store_bought(inven_type *); int store_bought_p(inven_type *); void sample(struct inven_type *); void identify(int *); void unmagic_name(struct inven_type *); void objdes(char *, struct inven_type *, int); void invcopy(inven_type *, int); void desc_charges(int); void desc_remain(int); /* dungeon.c */ void dungeon(void); /* eat.c */ void eat(void); /* files.c */ void init_scorefile(void); void read_times(void); void helpfile(char *); void print_objects(void); #ifdef MAC int file_character(void); #else int file_character(char *); #endif /* generate.c */ void generate_cave(void); #ifdef VMS /* getch.c */ int kbhit (void); void user_name (char *); void vms_crmode (void); void vms_nocrmode (void); int opengetch (void); int closegetch (void); char vms_getch (void); #endif /* help.c */ void ident_char(void); /* io.c */ #ifdef SIGTSTP int suspend(void); #endif void init_curses(void); void moriaterm(void); void put_buffer(char *, int, int); void put_qio(void); void restore_term(void); void shell_out(void); char inkey(void); void flush(void); void erase_line(int, int); void clear_screen(void); void clear_from(int); void print(char, int, int); void move_cursor_relative(int, int); void count_msg_print(char *); void prt(char *, int, int); void move_cursor(int, int); void msg_print(char *); int get_check(char *); int get_com(char *, char *); int get_string(char *, int, int, int); void pause_line(int); void pause_exit(int, int); void save_screen(void); void restore_screen(void); void bell(void); void screen_map(void); /* magic.c */ void cast(void); /* main.c */ int main(int, char **); /* misc1.c */ void init_seeds(int32u); void set_seed(int32u); void reset_seed(void); int check_time(void); int randint(int); int randnor(int, int); int bit_pos(int32u *); int in_bounds(int, int); void panel_bounds(void); int get_panel(int, int, int); int panel_contains(int, int); int distance(int, int, int, int); int next_to_wall(int, int); int next_to_corr(int, int); int damroll(int, int); int pdamroll(unsigned char *); int los(int, int, int, int); unsigned char loc_symbol(int, int); int test_light(int, int); void prt_map(void); int compact_monsters(void); void add_food(int); int popm(void); int max_hp(unsigned char *); int place_monster(int, int, int, int); void place_win_monster(void); int get_mons_num(int); void alloc_monster(int, int, int); int summon_monster(int * ,int *, int); int summon_undead(int *, int *); int popt(void); void pusht(int8u); int magik(int); int m_bonus(int, int, int); /* misc2.c */ void magic_treasure(int, int); void set_options(void); /* misc3.c */ void place_trap(int, int, int); void place_rubble(int, int); void place_gold(int, int); int get_obj_num(int, int); void place_object(int, int, int); void alloc_object(int (*)(), int, int); void random_object(int, int, int); void cnv_stat(int8u, char *); void prt_stat(int); void prt_field(char *, int, int); int stat_adj(int); int chr_adj(void); int con_adj(void); char *title_string(void); void prt_title(void); void prt_level(void); void prt_cmana(void); void prt_mhp(void); void prt_chp(void); void prt_pac(void); void prt_gold(void); void prt_depth(void); void prt_hunger(void); void prt_blind(void); void prt_confused(void); void prt_afraid(void); void prt_poisoned(void); void prt_state(void); void prt_speed(void); void prt_study(void); void prt_winner(void); int8u modify_stat(int, int16); void set_use_stat(int); int inc_stat(int); int dec_stat(int); int res_stat(int); void bst_stat(int, int); int tohit_adj(void); int toac_adj(void); int todis_adj(void); int todam_adj(void); void prt_stat_block(void); void draw_cave(void); void put_character(void); void put_stats(void); char *likert(int, int); void put_misc1(void); void put_misc2(void); void put_misc3(void); void display_char(void); void get_name(void); void change_name(void); void inven_destroy(int); void take_one_item(struct inven_type *, struct inven_type *); void inven_drop(int, int); int inven_damage(int (*)(), int); int weight_limit(void); int inven_check_num(struct inven_type *); int inven_check_weight(struct inven_type *); void check_strength(void); int inven_carry(struct inven_type *); int spell_chance(int); void print_spells(int *, int, int, int); int get_spell(int *, int, int *, int *, char *, int); void calc_spells(int); void gain_spells(void); void calc_mana(int); void prt_experience(void); void calc_hitpoints(void); void insert_str(char *, char *, char *); void insert_lnum(char *, char *, int32, int); int enter_wiz_mode(void); int attack_blows(int, int *); int tot_dam(struct inven_type *, int, int); int critical_blow(int, int, int, int); int mmove(int, int *, int *); int player_saves(void); int find_range(int, int, int *, int *); void teleport(int); /* misc4.c */ void scribe_object(void); void add_inscribe(struct inven_type *, int8u); void inscribe(struct inven_type *, char *); void check_view(void); /* monsters.c */ /* moria1.c */ void change_speed(int); void py_bonuses(struct inven_type *, int); void calc_bonuses(void); int show_inven(int, int, int, int, char *); char *describe_use(int); int show_equip(int, int); void takeoff(int, int); int verify(char *, int); void inven_command(char); int get_item(int *, char *, int, int, char *, char *); int no_light(void); int get_dir(char *, int *); int get_alldir(char *, int *); void move_rec(int, int, int, int); void light_room(int, int); void lite_spot(int, int); void move_light(int, int, int, int); void disturb(int, int); void search_on(void); void search_off(void); void rest(void); void rest_off(void); int test_hit(int, int, int, int, int); void take_hit(int, char *); /* moria2.c */ void change_trap(int, int); void search(int, int, int); void find_init(int); void find_run(void); void end_find(void); void area_affect(int, int, int); int minus_ac(int32u); void corrode_gas(char *); void poison_gas(int, char *); void fire_dam(int, char *); void cold_dam(int, char *); void light_dam(int, char *); void acid_dam(int, char *); /* moria3.c */ int cast_spell(char * ,int, int *, int *); void delete_monster(int); void fix1_delete_monster(int); void fix2_delete_monster(int); int delete_object(int, int); int32u monster_death(int, int, int32u); int mon_take_hit(int, int); void py_attack(int, int); void move_char(int, int); void chest_trap(int, int); void openobject(void); void closeobject(void); int twall(int, int, int, int); /* moria4.c */ void tunnel(int); void disarm_trap(void); void look(void); void throw_object(void); void bash(void); #ifdef MSDOS /* ms_misc.c */ void user_name(char *); char *getlogin(void); #ifdef __TURBOC__ void sleep(unsigned); #else unsigned int sleep(int); #endif void error(char *, ...); void warn(char *, ...); void msdos_init(void); void msdos_raw(void); void msdos_noraw(void); int bios_getch(void); int msdos_getch(void); void bios_clear(void); void msdos_intro(void); void bios_clear(void); #endif /* potions.c */ void quaff(void); /* prayer.c */ void pray(void); /* recall.c */ int bool_roff_recall(int); int roff_recall(int); /* rnd.c */ int32u get_rnd_seed(void); void set_rnd_seed(int32u); int32 rnd(void); /* save.c */ #ifdef MAC int save_char(int); #else int save_char(void); #endif int _save_char(char *); int get_char(int *); void set_fileptr(FILE *); void wr_highscore(high_scores *); void rd_highscore(high_scores *); /* scrolls.c */ void read_scroll(void); /* sets.c */ int set_room(int); int set_corr(int); int set_floor(int); int set_corrodes(inven_type *); int set_flammable(inven_type *); int set_frost_destroy(inven_type *); int set_acid_affect(inven_type *); int set_lightning_destroy(inven_type *); int set_null(inven_type *); int set_acid_destroy(inven_type *); int set_fire_destroy(inven_type *); int set_large(inven_type *); int general_store(int); int armory(int); int weaponsmith(int); int temple(int); int alchemist(int); int magic_shop(int); #ifdef MAC int store_buy(int, int); #endif /* signals.c */ void nosignals(void); void signals(void); void init_signals(void); void ignore_signals(void); void default_signals(void); void restore_signals(void); /* spells.c */ void monster_name(char *, struct monster_type *, struct creature_type *); void lower_monster_name(char *, struct monster_type *, struct creature_type *); int sleep_monsters1(int, int); int detect_treasure(void); int detect_object(void); int detect_trap(void); int detect_sdoor(void); int detect_invisible(void); int light_area(int, int); int unlight_area(int, int); void map_area(void); int ident_spell(void); int aggravate_monster(int); int trap_creation(void); int door_creation(void); int td_destroy(void); int detect_monsters(void); void light_line(int, int, int); void starlite(int, int); int disarm_all(int, int, int); void get_flags(int, int32u *, int *, int (**)()); void fire_bolt(int, int, int, int, int, char *); void fire_ball(int, int, int, int, int, char *); void breath(int, int, int, int, char *, int); int recharge(int); int hp_monster(int, int, int, int); int drain_life(int, int, int); int speed_monster(int, int, int, int); int confuse_monster(int, int, int); int sleep_monster(int, int, int); int wall_to_mud(int, int, int); int td_destroy2(int, int, int); int poly_monster(int, int, int); int build_wall(int, int, int); int clone_monster(int, int, int); void teleport_away(int, int); void teleport_to(int, int); int teleport_monster(int, int, int); int mass_genocide(void); int genocide(void); int speed_monsters(int); int sleep_monsters2(void); int mass_poly(void); int detect_evil(void); int hp_player(int); int cure_confusion(void); int cure_blindness(void); int cure_poison(void); int remove_fear(void); void earthquake(void); int protect_evil(void); void create_food(void); int dispel_creature(int, int); int turn_undead(void); void warding_glyph(void); void lose_str(void); void lose_int(void); void lose_wis(void); void lose_dex(void); void lose_con(void); void lose_chr(void); void lose_exp(int32); int slow_poison(void); void bless(int); void detect_inv2(int); void destroy_area(int, int); int enchant(int16 *, int16); int remove_curse(void); int restore_level(void); /* staffs.c */ void use(void); /* store1.c */ int32 item_value(struct inven_type *); int32 sell_price(int, int32 *, int32 *, struct inven_type *); int store_check_num(struct inven_type *, int); void store_carry(int, int *, struct inven_type *); void store_destroy(int, int, int); void store_init(void); void store_maint(void); int noneedtobargain(int, int32); void updatebargain(int, int32, int32); /* store2.c */ void enter_store(int); /* treasur1.c */ /* treasur2.c */ #ifdef VMS /* uexit.c */ void uexit (int); #endif #ifdef unix /* unix.c */ int check_input(int); #if 0 int system_cmd(char *); #endif void user_name(char *); int tilde(char *, char *); FILE *tfopen(char *, char *); int topen(char *, int, int); #endif /* variable.c */ /* wands.c */ void aim(void); /* wizard.c */ void wizard_light(void); void change_character(void); void wizard_create(void); #else /* !defined (LINT_ARGS) */ #ifdef ATARI_ST /* atarist.c */ int check_input (); void user_name (); int access (); void chmod (); #endif /* create.c */ void create_character(); /* creature.c */ void update_mon(); int multiply_monster(); void creatures(); /* death.c */ void display_scores(); int duplicate_character(); int32 total_points(); void exit_game(); /* desc.c */ int is_a_vowel(); void magic_init(); int16 object_offset(); void known1(); int known1_p(); void known2(); int known2_p(); void clear_known2(); void clear_empty(); void store_bought(); int store_bought_p(); void sample(); void identify(); void unmagic_name(); void objdes(); void invcopy(); void desc_charges(); void desc_remain(); /* dungeon.c */ void dungeon(); /* eat.c */ void eat(); /* files.c */ void init_scorefile(); void read_times(); void helpfile(); void print_objects(); int file_character(); /* generate.c */ void generate_cave(); #ifdef VMS /* getch.c */ int kbhit (); void user_name (); void vms_crmode (); void vms_nocrmode (); int opengetch (); int closegetch (); char vms_getch (); #endif /* help.c */ void ident_char(); /* io.c */ #ifdef SIGTSTP int suspend(); #endif void init_curses(); void moriaterm(); void put_buffer(); void put_qio(); void restore_term(); void shell_out(); char inkey(); void flush(); void erase_line(); void clear_screen(); void clear_from(); void print(); void move_cursor_relative(); void count_msg_print(); void prt(); void move_cursor(); void msg_print(); int get_check(); int get_com(); int get_string(); void pause_line(); void pause_exit(); void save_screen(); void restore_screen(); void bell(); void screen_map(); /* magic.c */ void cast(); /* main.c */ int main(); /* misc1.c */ void init_seeds(); void set_seed(); void reset_seed(); int check_time(); int randint(); int randnor(); int bit_pos(); int in_bounds(); void panel_bounds(); int get_panel(); int panel_contains(); int distance(); int next_to_walls(); int next_to_corr(); int damroll(); int pdamroll(); int los(); unsigned char loc_symbol(); int test_light(); void prt_map(); int compact_monsters(); void add_food(); int popm(); int max_hp(); int place_monster(); void place_win_monster(); int get_mons_num(); void alloc_monster(); int summon_monster(); int summon_undead(); int popt(); void pusht(); int magik(); int m_bonus(); /* misc2.c */ void magic_treasure(); void set_options(); /* misc3.c */ void place_trap(); void place_rubble(); void place_gold(); int get_obj_num(); void place_object(); void alloc_object(); void random_object(); void cnv_stat(); void prt_stat(); void prt_field(); int stat_adj(); int chr_adj(); int con_adj(); char *title_string(); void prt_title(); void prt_level(); void prt_cmana(); void prt_mhp(); void prt_chp(); void prt_pac(); void prt_gold(); void prt_depth(); void prt_hunger(); void prt_blind(); void prt_confused(); void prt_afraid(); void prt_poisoned(); void prt_state(); void prt_speed(); void prt_study(); void prt_winner(); int8u modify_stat(); void set_use_stat(); int inc_stat(); int dec_stat(); int res_stat(); void bst_stat(); int tohit_adj(); int toac_adj(); int todis_adj(); int todam_adj(); void prt_stat_block(); void draw_cave(); void put_character(); void put_stats(); char *likert(); void put_misc1(); void put_misc2(); void put_misc3(); void display_char(); void get_name(); void change_name(); void inven_destroy(); void take_one_item(); void inven_drop(); int inven_damage(); int weight_limit(); int inven_check_num(); int inven_check_weight(); void check_strength(); int inven_carry(); int spell_chance(); void print_spells(); int get_spell(); void calc_spells(); void gain_spells(); void calc_mana(); void prt_experience(); void calc_hitpoints(); void insert_str(); void insert_lnum(); int enter_wiz_mode(); int attack_blows(); int tot_dam(); int critical_blow(); int mmove(); int player_saves(); int find_range(); void teleport(); /* misc4.c */ void scribe_object(); void add_inscribe(); void inscribe(); void check_view(); /* monsters.c */ /* moria1.c */ void change_speed(); void py_bonuses(); void calc_bonuses(); int show_inven(); char *describe_use(); int show_equip(); void takeoff(); int verify(); void inven_command(); int get_item(); int no_light(); int get_dir(); int get_alldir(); void move_rec(); void light_room(); void lite_spot(); void move_light(); void disturb(); void search_on(); void search_off(); void rest(); void rest_off(); int test_hit(); void take_hit(); /* moria2.c */ void change_trap(); void search(); void find_init(); void find_run(); void end_find(); void area_affect(); int minus_ac(); void corrode_gas(); void poison_gas(); void fire_dam(); void cold_dam(); void light_dam(); void acid_dam(); /* moria3.c */ int cast_spell(); void delete_monster(); void fix1_delete_monster(); void fix2_delete_monster(); int delete_object(); int32u monster_death(); int mon_take_hit(); void py_attack(); void move_char(); void chest_trap(); void openobject(); void closeobject(); int twall(); /* moria4.c */ void tunnel(); void disarm_trap(); void look(); void throw_object(); void bash(); #ifdef MSDOS /* ms_misc.c */ void user_name(); char *getlogin(); #ifdef __TURBOC__ void sleep(); #else unsigned int sleep(); #endif #if 0 void error(); void warn(); #else /* Because an empty parameter list in a declaration can not match a parameter list with an elipsis in a definition. */ void error (char *fmt, ...); void warn (char *fmt, ...); #endif void msdos_init(); void msdos_raw(); void msdos_noraw(); int bios_getch(); int msdos_getch(); void bios_clear(); void msdos_intro(); void bios_clear(); #endif /* potions.c */ void quaff(); /* prayer.c */ void pray(); /* recall.c */ int bool_roff_recall(); int roff_recall(); /* rnd.c */ int32u get_rnd_seed(); void set_rnd_seed(); int32 rnd(); /* save.c */ int save_char(); int _save_char(); int get_char(); void set_fileptr(); void wr_highscore(); void rd_highscore(); /* scrolls.c */ void read_scroll(); /* sets.c */ int set_room(); int set_corr(); int set_floor(); int set_corrodes(); int set_flammable(); int set_frost_destroy(); int set_acid_affect(); int set_lightning_destroy(); int set_null(); int set_acid_destroy(); int set_fire_destroy(); int set_large(); int general_store(); int armory(); int weaponsmith(); int temple(); int alchemist(); int magic_shop(); #ifdef MAC int store_buy(); #endif /* signals.c */ void nosignals(); void signals(); void init_signals(); void ignore_signals(); void default_signals(); void restore_signals(); /* spells.c */ void monster_name(); void lower_monster_name(); int sleep_monsters1(); int detect_treasure(); int detect_object(); int detect_trap(); int detect_sdoor(); int detect_invisible(); int light_area(); int unlight_area(); void map_area(); int ident_spell(); int aggravate_monster(); int trap_creation(); int door_creation(); int td_destroy(); int detect_monsters(); void light_line(); void starlite(); int disarm_all(); void get_flags(); void fire_bolt(); void fire_ball(); void breath(); int recharge(); int hp_monster(); int drain_life(); int speed_monster(); int confuse_monster(); int sleep_monster(); int wall_to_mud(); int td_destroy2(); int poly_monster(); int build_wall(); int clone_monster(); void teleport_away(); void teleport_to(); int teleport_monster(); int mass_genocide(); int genocide(); int speed_monsters(); int sleep_monsters2(); int mass_poly(); int detect_evil(); int hp_player(); int cure_confusion(); int cure_blindness(); int cure_poison(); int remove_fear(); void earthquake(); int protect_evil(); void create_food(); int dispel_creature(); int turn_undead(); void warding_glyph(); void lose_str(); void lose_int(); void lose_wis(); void lose_dex(); void lose_con(); void lose_chr(); void lose_exp(); int slow_poison(); void bless(); void detect_inv2(); void destroy_area(); int enchant(); int remove_curse(); int restore_level(); /* staffs.c */ void use(); /* store1.c */ int32 item_value(); int32 sell_price(); int store_check_num(); void store_carry(); void store_destroy(); void store_init(); void store_maint(); int noneedtobargain(); void updatebargain(); /* store2.c */ void enter_store(); /* treasur1.c */ /* treasur2.c */ #ifdef VMS /* uexit.c */ void uexit (); #endif #ifdef unix /* unix.c */ int check_input(); #if 0 int system_cmd(); #endif void user_name(); int tilde(); FILE *tfopen(); int topen(); #endif /* variable.c */ /* wands.c */ void aim(); /* wizard.c */ void wizard_light(); void change_character(); void wizard_create(); #endif #ifdef unix /* call functions which expand tilde before calling open/fopen */ #define open topen #define fopen tfopen #endif /* st-stuff.c for the atari ST */ #if defined(atarist) && defined(__GNUC__) extern char extended_file_name[80]; #endif moria-5.6.debian.1/source/eat.c0000644000175000017500000001273111074756544014421 0ustar pjbpjb/* source/eat.c: food code Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #ifdef USG #include #else #include #endif /* Eat some food. -RAK- */ void eat() { int32u i; int j, k, item_val, ident; register struct flags *f_ptr; register struct misc *m_ptr; register inven_type *i_ptr; #ifdef ATARIST_MWC int32u holder; #endif free_turn_flag = TRUE; if (inven_ctr == 0) msg_print("But you are not carrying anything."); else if (!find_range(TV_FOOD, TV_NEVER, &j, &k)) msg_print("You are not carrying any food."); else if (get_item(&item_val, "Eat what?", j, k, CNIL, CNIL)) { i_ptr = &inventory[item_val]; free_turn_flag = FALSE; i = i_ptr->flags; ident = FALSE; while (i != 0) { j = bit_pos(&i) + 1; /* Foods */ switch(j) { case 1: f_ptr = &py.flags; f_ptr->poisoned += randint(10) + i_ptr->level; ident = TRUE; break; case 2: f_ptr = &py.flags; f_ptr->blind += randint(250) + 10*i_ptr->level + 100; draw_cave(); msg_print("A veil of darkness surrounds you."); ident = TRUE; break; case 3: f_ptr = &py.flags; f_ptr->afraid += randint(10) + i_ptr->level; msg_print("You feel terrified!"); ident = TRUE; break; case 4: f_ptr = &py.flags; f_ptr->confused += randint(10) + i_ptr->level; msg_print("You feel drugged."); ident = TRUE; break; case 5: f_ptr = &py.flags; f_ptr->image += randint(200) + 25*i_ptr->level + 200; msg_print("You feel drugged."); ident = TRUE; break; case 6: ident = cure_poison(); break; case 7: ident = cure_blindness(); break; case 8: f_ptr = &py.flags; if (f_ptr->afraid > 1) { f_ptr->afraid = 1; ident = TRUE; } break; case 9: ident = cure_confusion(); break; case 10: ident = TRUE; lose_str(); break; case 11: ident = TRUE; lose_con(); break; #if 0 /* 12 through 15 are not used */ case 12: ident = TRUE; lose_int(); break; case 13: ident = TRUE; lose_wis(); break; case 14: ident = TRUE; lose_dex(); break; case 15: ident = TRUE; lose_chr(); break; #endif case 16: if (res_stat (A_STR)) { msg_print("You feel your strength returning."); ident = TRUE; } break; case 17: if (res_stat (A_CON)) { msg_print("You feel your health returning."); ident = TRUE; } break; case 18: if (res_stat (A_INT)) { msg_print("Your head spins a moment."); ident = TRUE; } break; case 19: if (res_stat (A_WIS)) { msg_print("You feel your wisdom returning."); ident = TRUE; } break; case 20: if (res_stat (A_DEX)) { msg_print("You feel more dextrous."); ident = TRUE; } break; case 21: if (res_stat (A_CHR)) { msg_print("Your skin stops itching."); ident = TRUE; } break; case 22: ident = hp_player(randint(6)); break; case 23: ident = hp_player(randint(12)); break; case 24: ident = hp_player(randint(18)); break; #if 0 /* 25 is not used */ case 25: ident = hp_player(damroll(3, 6)); break; #endif case 26: ident = hp_player(damroll(3, 12)); break; case 27: take_hit(randint(18), "poisonous food."); ident = TRUE; break; #if 0 /* 28 through 30 are not used */ case 28: take_hit(randint(8), "poisonous food."); ident = TRUE; break; case 29: take_hit(damroll(2, 8), "poisonous food."); ident = TRUE; break; case 30: take_hit(damroll(3, 8), "poisonous food."); ident = TRUE; break; #endif default: msg_print("Internal error in eat()"); break; } /* End of food actions. */ } if (ident) { if (!known1_p(i_ptr)) { /* use identified it, gain experience */ m_ptr = &py.misc; /* round half-way case up */ m_ptr->exp += (i_ptr->level + (m_ptr->lev >> 1)) / m_ptr->lev; prt_experience(); identify (&item_val); i_ptr = &inventory[item_val]; } } else if (!known1_p(i_ptr)) sample (i_ptr); add_food(i_ptr->p1); #ifdef ATARIST_MWC py.flags.status &= ~(holder = PY_WEAK|PY_HUNGRY); #else py.flags.status &= ~(PY_WEAK|PY_HUNGRY); #endif prt_hunger(); desc_remain(item_val); inven_destroy(item_val); } } moria-5.6.debian.1/source/potions.c0000644000175000017500000002151511074756544015343 0ustar pjbpjb/* source/potions.c: code for potions Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #ifdef USG #include #else #include #endif /* Potions for the quaffing -RAK- */ void quaff() { int32u i, l; int j, k, item_val; int ident; register inven_type *i_ptr; register struct misc *m_ptr; register struct flags *f_ptr; #if 0 /* used by ifdefed out learn_spell potion */ register class_type *c_ptr; #endif free_turn_flag = TRUE; if (inven_ctr == 0) msg_print("But you are not carrying anything."); else if (!find_range(TV_POTION1, TV_POTION2, &j, &k)) msg_print("You are not carrying any potions."); else if (get_item(&item_val, "Quaff which potion?", j, k, CNIL, CNIL)) { i_ptr = &inventory[item_val]; i = i_ptr->flags; free_turn_flag = FALSE; ident = FALSE; if (i == 0) { msg_print ("You feel less thirsty."); ident = TRUE; } else while (i != 0) { j = bit_pos(&i) + 1; if (i_ptr->tval == TV_POTION2) j += 32; /* Potions */ switch(j) { case 1: if (inc_stat (A_STR)) { msg_print("Wow! What bulging muscles!"); ident = TRUE; } break; case 2: ident = TRUE; lose_str(); break; case 3: if (res_stat (A_STR)) { msg_print("You feel warm all over."); ident = TRUE; } break; case 4: if (inc_stat (A_INT)) { msg_print("Aren't you brilliant!"); ident = TRUE; } break; case 5: ident = TRUE; lose_int(); break; case 6: if (res_stat (A_INT)) { msg_print("You have have a warm feeling."); ident = TRUE; } break; case 7: if (inc_stat (A_WIS)) { msg_print("You suddenly have a profound thought!"); ident = TRUE; } break; case 8: ident = TRUE; lose_wis(); break; case 9: if (res_stat (A_WIS)) { msg_print("You feel your wisdom returning."); ident = TRUE; } break; case 10: if (inc_stat (A_CHR)) { msg_print("Gee, ain't you cute!"); ident = TRUE; } break; case 11: ident = TRUE; lose_chr(); break; case 12: if (res_stat (A_CHR)) { msg_print("You feel your looks returning."); ident = TRUE; } break; case 13: ident = hp_player(damroll(2, 7)); break; case 14: ident = hp_player(damroll(4, 7)); break; case 15: ident = hp_player(damroll(6, 7)); break; case 16: ident = hp_player(1000); break; case 17: if (inc_stat (A_CON)) { msg_print("You feel tingly for a moment."); ident = TRUE; } break; case 18: m_ptr = &py.misc; if (m_ptr->exp < MAX_EXP) { l = (m_ptr->exp / 2) + 10; if (l > 100000L) l = 100000L; m_ptr->exp += l; msg_print("You feel more experienced."); prt_experience(); ident = TRUE; } break; case 19: f_ptr = &py.flags; if (!f_ptr->free_act) { /* paralysis must == 0, otherwise could not drink potion */ msg_print("You fall asleep."); f_ptr->paralysis += randint(4) + 4; ident = TRUE; } break; case 20: f_ptr = &py.flags; if (f_ptr->blind == 0) { msg_print("You are covered by a veil of darkness."); ident = TRUE; } f_ptr->blind += randint(100) + 100; break; case 21: f_ptr = &py.flags; if (f_ptr->confused == 0) { msg_print("Hey! This is good stuff! * Hick! *"); ident = TRUE; } f_ptr->confused += randint(20) + 12; break; case 22: f_ptr = &py.flags; if (f_ptr->poisoned == 0) { msg_print("You feel very sick."); ident = TRUE; } f_ptr->poisoned += randint(15) + 10; break; case 23: if (py.flags.fast == 0) ident = TRUE; py.flags.fast += randint(25) + 15; break; case 24: if (py.flags.slow == 0) ident = TRUE; py.flags.slow += randint(25) + 15; break; case 26: if (inc_stat (A_DEX)) { msg_print("You feel more limber!"); ident = TRUE; } break; case 27: if (res_stat (A_DEX)) { msg_print("You feel less clumsy."); ident = TRUE; } break; case 28: if (res_stat (A_CON)) { msg_print("You feel your health returning!"); ident = TRUE; } break; case 29: ident = cure_blindness(); break; case 30: ident = cure_confusion(); break; case 31: ident = cure_poison(); break; #if 0 case 33: /* this is no longer useful, now that there is a 'G'ain magic spells command */ m_ptr = &py.misc; c_ptr = &class[m_ptr->pclass]; if (c_ptr->spell == MAGE) { calc_spells(A_INT); calc_mana(A_INT); } else if (c_ptr->spell == PRIEST) { calc_spells(A_WIS); calc_mana(A_WIS); } else { /* A warrior learns something about his equipment. -CJS- */ inven_type *w_ptr; vtype tmp_str; extern char *describe_use (); for (k = 22; k < INVEN_ARRAY_SIZE; k++) { w_ptr = &inventory[k]; if (w_ptr->tval != TV_NOTHING && enchanted (w_ptr)) { (void) sprintf (tmp_str, "There's something about what you are %s...", describe_use(k)); msg_print (tmp_str); add_inscribe(w_ptr, ID_MAGIK); ident = TRUE; } } } break; #endif case 34: if (py.misc.exp > 0) { int32 m, scale; msg_print("You feel your memories fade."); /* Lose between 1/5 and 2/5 of your experience */ m = py.misc.exp / 5; if (py.misc.exp > MAX_SHORT) { scale = MAX_LONG / py.misc.exp; m += (randint((int)scale) * py.misc.exp) / (scale * 5); } else m += randint((int)py.misc.exp) / 5; lose_exp(m); ident = TRUE; } break; case 35: f_ptr = &py.flags; (void) cure_poison(); if (f_ptr->food > 150) f_ptr->food = 150; f_ptr->paralysis = 4; msg_print("The potion makes you vomit!"); ident = TRUE; break; case 36: if (py.flags.invuln == 0) ident = TRUE; py.flags.invuln += randint(10) + 10; break; case 37: if (py.flags.hero == 0) ident = TRUE; py.flags.hero += randint(25) + 25; break; case 38: if (py.flags.shero == 0) ident = TRUE; py.flags.shero += randint(25) + 25; break; case 39: ident = remove_fear(); break; case 40: ident = restore_level(); break; case 41: f_ptr = &py.flags; if (f_ptr->resist_heat == 0) ident = TRUE; f_ptr->resist_heat += randint(10) + 10; break; case 42: f_ptr = &py.flags; if (f_ptr->resist_cold == 0) ident = TRUE; f_ptr->resist_cold += randint(10) + 10; break; case 43: if (py.flags.detect_inv == 0) ident = TRUE; detect_inv2(randint(12)+12); break; case 44: ident = slow_poison(); break; case 45: ident = cure_poison(); break; case 46: m_ptr = &py.misc; if (m_ptr->cmana < m_ptr->mana) { m_ptr->cmana = m_ptr->mana; ident = TRUE; msg_print("Your feel your head clear."); prt_cmana(); } break; case 47: f_ptr = &py.flags; if (f_ptr->tim_infra == 0) { msg_print("Your eyes begin to tingle."); ident = TRUE; } f_ptr->tim_infra += 100 + randint(100); break; default: msg_print ("Internal error in potion()"); break; } /* End of Potions. */ } if (ident) { if (!known1_p(i_ptr)) { m_ptr = &py.misc; /* round half-way case up */ m_ptr->exp += (i_ptr->level + (m_ptr->lev >> 1)) / m_ptr->lev; prt_experience(); identify(&item_val); i_ptr = &inventory[item_val]; } } else if (!known1_p(i_ptr)) sample (i_ptr); add_food(i_ptr->p1); desc_remain(item_val); inven_destroy(item_val); } } moria-5.6.debian.1/source/wands.c0000644000175000017500000001224211074756544014761 0ustar pjbpjb/* source/wands.c: wand code Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #ifdef USG #ifndef ATARIST_MWC #include #endif #else #include #endif /* Wands for the aiming. */ void aim() { int32u i; register int l, ident; int item_val, j, k, chance, dir; register inven_type *i_ptr; register struct misc *m_ptr; free_turn_flag = TRUE; if (inven_ctr == 0) msg_print("But you are not carrying anything."); else if (!find_range(TV_WAND, TV_NEVER, &j, &k)) msg_print("You are not carrying any wands."); else if (get_item(&item_val, "Aim which wand?", j, k, CNIL, CNIL)) { i_ptr = &inventory[item_val]; free_turn_flag = FALSE; if (get_dir(CNIL, &dir)) { if (py.flags.confused > 0) { msg_print("You are confused."); do { dir = randint(9); } while (dir == 5); } ident = FALSE; m_ptr = &py.misc; chance = m_ptr->save + stat_adj(A_INT) - (int)i_ptr->level + (class_level_adj[m_ptr->pclass][CLA_DEVICE] * m_ptr->lev / 3); if (py.flags.confused > 0) chance = chance / 2; if ((chance < USE_DEVICE) && (randint(USE_DEVICE - chance + 1) == 1)) chance = USE_DEVICE; /* Give everyone a slight chance */ if (chance <= 0) chance = 1; if (randint(chance) < USE_DEVICE) msg_print("You failed to use the wand properly."); else if (i_ptr->p1 > 0) { i = i_ptr->flags; (i_ptr->p1)--; while (i != 0) { j = bit_pos(&i) + 1; k = char_row; l = char_col; /* Wands */ switch(j) { case 1: msg_print("A line of blue shimmering light appears."); light_line(dir, char_row, char_col); ident = TRUE; break; case 2: fire_bolt(GF_LIGHTNING, dir, k, l, damroll(4, 8), spell_names[8]); ident = TRUE; break; case 3: fire_bolt(GF_FROST, dir, k, l, damroll(6, 8), spell_names[14]); ident = TRUE; break; case 4: fire_bolt(GF_FIRE, dir, k, l, damroll(9, 8), spell_names[22]); ident = TRUE; break; case 5: ident = wall_to_mud(dir, k, l); break; case 6: ident = poly_monster(dir, k, l); break; case 7: ident = hp_monster(dir, k, l, -damroll(4, 6)); break; case 8: ident = speed_monster(dir, k, l, 1); break; case 9: ident = speed_monster(dir, k, l, -1); break; case 10: ident = confuse_monster(dir, k, l); break; case 11: ident = sleep_monster(dir, k, l); break; case 12: ident = drain_life(dir, k, l); break; case 13: ident = td_destroy2(dir, k, l); break; case 14: fire_bolt(GF_MAGIC_MISSILE, dir, k, l, damroll(2, 6), spell_names[0]); ident = TRUE; break; case 15: ident = build_wall(dir, k, l); break; case 16: ident = clone_monster(dir, k, l); break; case 17: ident = teleport_monster(dir, k, l); break; case 18: ident = disarm_all(dir, k, l); break; case 19: fire_ball(GF_LIGHTNING, dir, k, l, 32, "Lightning Ball"); ident = TRUE; break; case 20: fire_ball(GF_FROST, dir, k, l, 48, "Cold Ball"); ident = TRUE; break; case 21: fire_ball(GF_FIRE, dir, k, l, 72, spell_names[28]); ident = TRUE; break; case 22: fire_ball(GF_POISON_GAS, dir, k, l, 12, spell_names[6]); ident = TRUE; break; case 23: fire_ball(GF_ACID, dir, k, l, 60, "Acid Ball"); ident = TRUE; break; case 24: i = 1L << (randint(23) - 1); break; default: msg_print("Internal error in wands()"); break; } /* End of Wands. */ } if (ident) { if (!known1_p(i_ptr)) { m_ptr = &py.misc; /* round half-way case up */ m_ptr->exp += (i_ptr->level +(m_ptr->lev >> 1)) / m_ptr->lev; prt_experience(); identify(&item_val); i_ptr = &inventory[item_val]; } } else if (!known1_p(i_ptr)) sample (i_ptr); desc_charges(item_val); } else { msg_print("The wand has no charges left."); if (!known2_p(i_ptr)) add_inscribe(i_ptr, ID_EMPTY); } } } } moria-5.6.debian.1/source/constant.h0000644000175000017500000005213711074756544015512 0ustar pjbpjb/* source/constant.h: global constants used by Moria Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ /*Note to the Wizard: - RAK - */ /* Tweaking these constants can *GREATLY* change the game. */ /* Two years of constant tuning have generated these */ /* values. Minor adjustments are encouraged, but you must */ /* be very careful not to unbalance the game. Moria was */ /* meant to be challenging, not a give away. Many */ /* adjustments can cause the game to act strangely, or even*/ /* cause errors. */ /*Addendum: - JEW - I have greatly expanded the number of defined constants. However, if you change anything below, without understanding EXACTLY how the game uses the number, the program may stop working correctly. Modify the constants at your own risk. */ #define CONSTANT_H_INCLUDED #ifndef CONFIG_H_INCLUDED Constant.h should always be included after config.h, because it uses some of the system defines set up there. #endif /* Current version number of Moria */ #define CUR_VERSION_MAJ 5 /* version 5.5.2 */ #define CUR_VERSION_MIN 5 #define PATCH_LEVEL 2 #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #define MAX_UCHAR 255 #define MAX_SHORT 32767 /* maximum short/long signed ints */ #define MAX_LONG 0x7FFFFFFFL /* Changing values below this line may be hazardous to your health! */ /* message line location */ #define MSG_LINE 0 /* number of messages to save in a buffer */ #define MAX_SAVE_MSG 22 /* How many messages to save -CJS- */ /* Dungeon size parameters */ #define MAX_HEIGHT 66 /* Multiple of 11; >= 22 */ #define MAX_WIDTH 198 /* Multiple of 33; >= 66 */ #define SCREEN_HEIGHT 22 #define SCREEN_WIDTH 66 #define QUART_HEIGHT (SCREEN_HEIGHT / 4) #define QUART_WIDTH (SCREEN_WIDTH / 4) /* Dungeon generation values */ /* Note: The entire design of dungeon can be changed by only */ /* slight adjustments here. */ #define DUN_TUN_RND 9 /* 1/Chance of Random direction */ #define DUN_TUN_CHG 70 /* Chance of changing direction (99 max) */ #define DUN_TUN_CON 15 /* Chance of extra tunneling */ #define DUN_ROO_MEA 32 /* Mean of # of rooms, standard dev2 */ #define DUN_TUN_PEN 25 /* % chance of room doors */ #define DUN_TUN_JCT 15 /* % chance of doors at tunnel junctions */ #define DUN_STR_DEN 5 /* Density of streamers */ #define DUN_STR_RNG 2 /* Width of streamers */ #define DUN_STR_MAG 3 /* Number of magma streamers */ #define DUN_STR_MC 90 /* 1/x chance of treasure per magma */ #define DUN_STR_QUA 2 /* Number of quartz streamers */ #define DUN_STR_QC 40 /* 1/x chance of treasure per quartz */ #define DUN_UNUSUAL 300 /* Level/x chance of unusual room */ /* Store constants */ #define MAX_OWNERS 18 /* Number of owners to choose from */ #define MAX_STORES 6 /* Number of different stores */ #define STORE_INVEN_MAX 24 /* Max number of discrete objs in inven */ #define STORE_CHOICES 26 /* NUMBER of items to choose stock from */ #define STORE_MAX_INVEN 18 /* Max diff objs in stock for auto buy */ #define STORE_MIN_INVEN 10 /* Min diff objs in stock for auto sell */ #define STORE_TURN_AROUND 9 /* Amount of buying and selling normally */ #define COST_ADJ 100 /* Adjust prices for buying and selling */ /* Treasure constants */ #define INVEN_ARRAY_SIZE 34 /* Size of inventory array(Do not change)*/ #define MAX_OBJ_LEVEL 50 /* Maximum level of magic in dungeon */ #define OBJ_GREAT 12 /* 1/n Chance of item being a Great Item */ /* Note that the following constants are all related, if you change one, you must also change all succeeding ones. Also, player_init[] and store_choice[] may also have to be changed. */ #define MAX_OBJECTS 420 /* Number of objects for universe */ #define MAX_DUNGEON_OBJ 344 /* Number of dungeon objects */ #define OBJ_OPEN_DOOR 367 #define OBJ_CLOSED_DOOR 368 #define OBJ_SECRET_DOOR 369 #define OBJ_UP_STAIR 370 #define OBJ_DOWN_STAIR 371 #define OBJ_STORE_DOOR 372 #define OBJ_TRAP_LIST 378 #define OBJ_RUBBLE 396 #define OBJ_MUSH 397 #define OBJ_SCARE_MON 398 #define OBJ_GOLD_LIST 399 #define OBJ_NOTHING 417 #define OBJ_RUINED_CHEST 418 #define OBJ_WIZARD 419 #define OBJECT_IDENT_SIZE 448 /* 7*64, see object_offset() in desc.c, could be MAX_OBJECTS o_o() rewritten */ #define MAX_GOLD 18 /* Number of different types of gold */ /* with MAX_TALLOC 150, it is possible to get compacting objects during level generation, although it is extremely rare */ #define MAX_TALLOC 175 /* Max objects per level */ #define MIN_TRIX 1 /* Minimum t_list index used */ #define TREAS_ROOM_ALLOC 7 /* Amount of objects for rooms */ #define TREAS_ANY_ALLOC 2 /* Amount of objects for corridors */ #define TREAS_GOLD_ALLOC 2 /* Amount of gold (and gems) */ /* Magic Treasure Generation constants */ /* Note: Number of special objects, and degree of enchantments */ /* can be adjusted here. */ #define OBJ_STD_ADJ 125 /* Adjust STD per level * 100 */ #define OBJ_STD_MIN 7 /* Minimum STD */ #define OBJ_TOWN_LEVEL 7 /* Town object generation level */ #define OBJ_BASE_MAGIC 15 /* Base amount of magic */ #define OBJ_BASE_MAX 70 /* Max amount of magic */ #define OBJ_DIV_SPECIAL 6 /* magic_chance/# special magic */ #define OBJ_DIV_CURSED 13 /* 10*magic_chance/# cursed items */ /* Constants describing limits of certain objects */ #define OBJ_LAMP_MAX 15000 /* Maximum amount that lamp can be filled*/ #define OBJ_BOLT_RANGE 18 /* Maximum range of bolts and balls */ #define OBJ_RUNE_PROT 3000 /* Rune of protection resistance */ /* Creature constants */ #define MAX_CREATURES 279 /* Number of creatures defined for univ */ #define N_MONS_ATTS 215 /* Number of monster attack types. */ /* with MAX_MALLOC 101, it is possible to get compacting monsters messages while breeding/cloning monsters */ #define MAX_MALLOC 125 /* Max that can be allocated */ #define MAX_MALLOC_CHANCE 160 /* 1/x chance of new monster each round */ #define MAX_MONS_LEVEL 40 /* Maximum level of creatures */ #define MAX_SIGHT 20 /* Maximum dis a creature can be seen */ #define MAX_SPELL_DIS 20 /* Maximum dis creat. spell can be cast */ #define MAX_MON_MULT 75 /* Maximum reproductions on a level */ #define MON_MULT_ADJ 7 /* High value slows multiplication */ #define MON_NASTY 50 /* 1/x chance of high level creat */ #define MIN_MALLOC_LEVEL 14 /* Minimum number of monsters/level */ #define MIN_MALLOC_TD 4 /* Number of people on town level (day) */ #define MIN_MALLOC_TN 8 /* Number of people on town level (night)*/ #define WIN_MON_TOT 2 /* Total number of "win" creatures */ #define WIN_MON_APPEAR 50 /* Level where winning creatures begin */ #define MON_SUMMON_ADJ 2 /* Adjust level of summoned creatures */ #define MON_DRAIN_LIFE 2 /* Percent of player exp drained per hit */ #define MAX_MON_NATTACK 4 /* Max num attacks (used in mons memory) -CJS-*/ #define MIN_MONIX 2 /* Minimum index in m_list (1 = py, 0 = no mon)*/ /* Trap constants */ #define MAX_TRAP 18 /* Number of defined traps */ #define SCARE_MONSTER 99 /* Descriptive constants */ #define MAX_COLORS 49 /* Used with potions */ #define MAX_MUSH 22 /* Used with mushrooms */ #define MAX_WOODS 25 /* Used with staffs */ #define MAX_METALS 25 /* Used with wands */ #define MAX_ROCKS 32 /* Used with rings */ #define MAX_AMULETS 11 /* Used with amulets */ #define MAX_TITLES 45 /* Used with scrolls */ #define MAX_SYLLABLES 153 /* Used with scrolls */ /* Player constants */ #define MAX_PLAYER_LEVEL 40 /* Maximum possible character level */ #define MAX_EXP 9999999L /* Maximum amount of experience -CJS- */ #define MAX_RACES 8 /* Number of defined races */ #define MAX_CLASS 6 /* Number of defined classes */ #define USE_DEVICE 3 /* x> Harder devices x< Easier devices */ #define MAX_BACKGROUND 128 /* Number of types of histories for univ */ #define PLAYER_FOOD_FULL 10000/* Getting full */ #define PLAYER_FOOD_MAX 15000/* Maximum food value, beyond is wasted */ #define PLAYER_FOOD_FAINT 300/* Character begins fainting */ #define PLAYER_FOOD_WEAK 1000/* Warn player that he is getting very low*/ #define PLAYER_FOOD_ALERT 2000/* Warn player that he is getting low */ #define PLAYER_REGEN_FAINT 33 /* Regen factor*2^16 when fainting */ #define PLAYER_REGEN_WEAK 98 /* Regen factor*2^16 when weak */ #define PLAYER_REGEN_NORMAL 197 /* Regen factor*2^16 when full */ #define PLAYER_REGEN_HPBASE 1442 /* Min amount hp regen*2^16 */ #define PLAYER_REGEN_MNBASE 524 /* Min amount mana regen*2^16 */ #define PLAYER_WEIGHT_CAP 130 /* "#"*(1/10 pounds) per strength point */ #define PLAYER_EXIT_PAUSE 2 /* Pause time before player can re-roll */ /* class level adjustment constants */ #define CLA_BTH 0 #define CLA_BTHB 1 #define CLA_DEVICE 2 #define CLA_DISARM 3 #define CLA_SAVE 4 /* this depends on the fact that CLA_SAVE values are all the same, if not, then should add a separate column for this */ #define CLA_MISC_HIT 4 #define MAX_LEV_ADJ 5 /* Base to hit constants */ #define BTH_PLUS_ADJ 3 /* Adjust BTH per plus-to-hit */ /* magic numbers for players inventory array */ #define INVEN_WIELD 22 /* must be first item in equipment list */ #define INVEN_HEAD 23 #define INVEN_NECK 24 #define INVEN_BODY 25 #define INVEN_ARM 26 #define INVEN_HANDS 27 #define INVEN_RIGHT 28 #define INVEN_LEFT 29 #define INVEN_FEET 30 #define INVEN_OUTER 31 #define INVEN_LIGHT 32 #define INVEN_AUX 33 /* Attribute indexes -CJS- */ #define A_STR 0 #define A_INT 1 #define A_WIS 2 #define A_DEX 3 #define A_CON 4 #define A_CHR 5 /* some systems have a non-ANSI definition of this, so undef it first */ #undef CTRL #define CTRL(x) (x & 0x1F) #define DELETE 0x7f #ifdef VMS #define ESCAPE '\032' /* Use CTRL-Z instead of ESCAPE. */ #else #define ESCAPE '\033' /* ESCAPE character -CJS- */ #endif /* This used to be NULL, but that was technically incorrect. CNIL is used instead of null to help avoid lint errors. */ #ifndef CNIL #define CNIL (char *)0 #endif /* Fval definitions: these describe the various types of dungeon floors and walls, if numbers above 15 are ever used, then the test against MIN_CAVE_WALL will have to be changed, also the save routines will have to be changed. */ #define NULL_WALL 0 #define DARK_FLOOR 1 #define LIGHT_FLOOR 2 #define MAX_CAVE_ROOM 2 #define CORR_FLOOR 3 #define BLOCKED_FLOOR 4 /* a corridor space with cl/st/se door or rubble */ #define MAX_CAVE_FLOOR 4 #define MAX_OPEN_SPACE 3 #define MIN_CLOSED_SPACE 4 #define TMP1_WALL 8 #define TMP2_WALL 9 #define MIN_CAVE_WALL 12 #define GRANITE_WALL 12 #define MAGMA_WALL 13 #define QUARTZ_WALL 14 #define BOUNDARY_WALL 15 /* Column for stats */ #define STAT_COLUMN 0 /* Class spell types */ #define NONE 0 #define MAGE 1 #define PRIEST 2 /* offsets to spell names in spell_names[] array */ #define SPELL_OFFSET 0 #define PRAYER_OFFSET 31 /* definitions for the psuedo-normal distribution generation */ #define NORMAL_TABLE_SIZE 256 #define NORMAL_TABLE_SD 64 /* the standard deviation for the table */ /* definitions for the player's status field */ #define PY_HUNGRY 0x00000001L #define PY_WEAK 0x00000002L #define PY_BLIND 0x00000004L #define PY_CONFUSED 0x00000008L #define PY_FEAR 0x00000010L #define PY_POISONED 0x00000020L #define PY_FAST 0x00000040L #define PY_SLOW 0x00000080L #define PY_SEARCH 0x00000100L #define PY_REST 0x00000200L #define PY_STUDY 0x00000400L #define PY_INVULN 0x00001000L #define PY_HERO 0x00002000L #define PY_SHERO 0x00004000L #define PY_BLESSED 0x00008000L #define PY_DET_INV 0x00010000L #define PY_TIM_INFRA 0x00020000L #define PY_SPEED 0x00040000L #define PY_STR_WGT 0x00080000L #define PY_PARALYSED 0x00100000L #define PY_REPEAT 0x00200000L #define PY_ARMOR 0x00400000L #define PY_STATS 0x3F000000L #define PY_STR 0x01000000L /* these 6 stat flags must be adjacent */ #define PY_INT 0x02000000L #define PY_WIS 0x04000000L #define PY_DEX 0x08000000L #define PY_CON 0x10000000L #define PY_CHR 0x20000000L #define PY_HP 0x40000000L #define PY_MANA 0x80000000L /* definitions for objects that can be worn */ #define TR_STATS 0x0000003FL /* the stats must be the low 6 bits */ #define TR_STR 0x00000001L #define TR_INT 0x00000002L #define TR_WIS 0x00000004L #define TR_DEX 0x00000008L #define TR_CON 0x00000010L #define TR_CHR 0x00000020L #define TR_SEARCH 0x00000040L #define TR_SLOW_DIGEST 0x00000080L #define TR_STEALTH 0x00000100L #define TR_AGGRAVATE 0x00000200L #define TR_TELEPORT 0x00000400L #define TR_REGEN 0x00000800L #define TR_SPEED 0x00001000L #define TR_EGO_WEAPON 0x0007E000L #define TR_SLAY_DRAGON 0x00002000L #define TR_SLAY_ANIMAL 0x00004000L #define TR_SLAY_EVIL 0x00008000L #define TR_SLAY_UNDEAD 0x00010000L #define TR_FROST_BRAND 0x00020000L #define TR_FLAME_TONGUE 0x00040000L #define TR_RES_FIRE 0x00080000L #define TR_RES_ACID 0x00100000L #define TR_RES_COLD 0x00200000L #define TR_SUST_STAT 0x00400000L #define TR_FREE_ACT 0x00800000L #define TR_SEE_INVIS 0x01000000L #define TR_RES_LIGHT 0x02000000L #define TR_FFALL 0x04000000L #define TR_BLIND 0x08000000L #define TR_TIMID 0x10000000L #define TR_TUNNEL 0x20000000L #define TR_INFRA 0x40000000L #define TR_CURSED 0x80000000L /* definitions for chests */ #define CH_LOCKED 0x00000001L #define CH_TRAPPED 0x000001F0L #define CH_LOSE_STR 0x00000010L #define CH_POISON 0x00000020L #define CH_PARALYSED 0x00000040L #define CH_EXPLODE 0x00000080L #define CH_SUMMON 0x00000100L /* definitions for creatures, cmove field */ #define CM_ALL_MV_FLAGS 0x0000003FL #define CM_ATTACK_ONLY 0x00000001L #define CM_MOVE_NORMAL 0x00000002L /* For Quylthulgs, which have no physical movement. */ #define CM_ONLY_MAGIC 0x00000004L #define CM_RANDOM_MOVE 0x00000038L #define CM_20_RANDOM 0x00000008L #define CM_40_RANDOM 0x00000010L #define CM_75_RANDOM 0x00000020L #define CM_SPECIAL 0x003F0000L #define CM_INVISIBLE 0x00010000L #define CM_OPEN_DOOR 0x00020000L #define CM_PHASE 0x00040000L #define CM_EATS_OTHER 0x00080000L #define CM_PICKS_UP 0x00100000L #define CM_MULTIPLY 0x00200000L #define CM_SMALL_OBJ 0x00800000L #define CM_CARRY_OBJ 0x01000000L #define CM_CARRY_GOLD 0x02000000L #define CM_TREASURE 0x7C000000L #define CM_TR_SHIFT 26 /* used for recall of treasure */ #define CM_60_RANDOM 0x04000000L #define CM_90_RANDOM 0x08000000L #define CM_1D2_OBJ 0x10000000L #define CM_2D2_OBJ 0x20000000L #define CM_4D2_OBJ 0x40000000L #define CM_WIN 0x80000000L /* creature spell definitions */ #define CS_FREQ 0x0000000FL #define CS_SPELLS 0x0001FFF0L #define CS_TEL_SHORT 0x00000010L #define CS_TEL_LONG 0x00000020L #define CS_TEL_TO 0x00000040L #define CS_LGHT_WND 0x00000080L #define CS_SER_WND 0x00000100L #define CS_HOLD_PER 0x00000200L #define CS_BLIND 0x00000400L #define CS_CONFUSE 0x00000800L #define CS_FEAR 0x00001000L #define CS_SUMMON_MON 0x00002000L #define CS_SUMMON_UND 0x00004000L #define CS_SLOW_PER 0x00008000L #define CS_DRAIN_MANA 0x00010000L #define CS_BREATHE 0x00F80000L /* may also just indicate resistance */ #define CS_BR_LIGHT 0x00080000L /* if no spell frequency set */ #define CS_BR_GAS 0x00100000L #define CS_BR_ACID 0x00200000L #define CS_BR_FROST 0x00400000L #define CS_BR_FIRE 0x00800000L /* creature defense flags */ #define CD_DRAGON 0x0001 #define CD_ANIMAL 0x0002 #define CD_EVIL 0x0004 #define CD_UNDEAD 0x0008 #define CD_WEAKNESS 0x03F0 #define CD_FROST 0x0010 #define CD_FIRE 0x0020 #define CD_POISON 0x0040 #define CD_ACID 0x0080 #define CD_LIGHT 0x0100 #define CD_STONE 0x0200 #define CD_NO_SLEEP 0x1000 #define CD_INFRA 0x2000 #define CD_MAX_HP 0x4000 /* inventory stacking subvals */ /* these never stack */ #define ITEM_NEVER_STACK_MIN 0 #define ITEM_NEVER_STACK_MAX 63 /* these items always stack with others of same subval, always treated as single objects, must be power of 2 */ #define ITEM_SINGLE_STACK_MIN 64 #define ITEM_SINGLE_STACK_MAX 192 /* see NOTE below */ /* these items stack with others only if have same subval and same p1, they are treated as a group for wielding, etc. */ #define ITEM_GROUP_MIN 192 #define ITEM_GROUP_MAX 255 /* NOTE: items with subval 192 are treated as single objects, but only stack with others of same subval if have the same p1 value, only used for torches */ /* id's used for object description, stored in object_ident */ #define OD_TRIED 0x1 #define OD_KNOWN1 0x2 /* id's used for item description, stored in i_ptr->ident */ #define ID_MAGIK 0x1 #define ID_DAMD 0x2 #define ID_EMPTY 0x4 #define ID_KNOWN2 0x8 #define ID_STOREBOUGHT 0x10 #define ID_SHOW_HITDAM 0x20 #define ID_NOSHOW_P1 0x40 #define ID_SHOW_P1 0x80 /* indexes into the special name table */ #define SN_NULL 0 #define SN_R 1 #define SN_RA 2 #define SN_RF 3 #define SN_RC 4 #define SN_RL 5 #define SN_HA 6 #define SN_DF 7 #define SN_SA 8 #define SN_SD 9 #define SN_SE 10 #define SN_SU 11 #define SN_FT 12 #define SN_FB 13 #define SN_FREE_ACTION 14 #define SN_SLAYING 15 #define SN_CLUMSINESS 16 #define SN_WEAKNESS 17 #define SN_SLOW_DESCENT 18 #define SN_SPEED 19 #define SN_STEALTH 20 #define SN_SLOWNESS 21 #define SN_NOISE 22 #define SN_GREAT_MASS 23 #define SN_INTELLIGENCE 24 #define SN_WISDOM 25 #define SN_INFRAVISION 26 #define SN_MIGHT 27 #define SN_LORDLINESS 28 #define SN_MAGI 29 #define SN_BEAUTY 30 #define SN_SEEING 31 #define SN_REGENERATION 32 #define SN_STUPIDITY 33 #define SN_DULLNESS 34 #define SN_BLINDNESS 35 #define SN_TIMIDNESS 36 #define SN_TELEPORTATION 37 #define SN_UGLINESS 38 #define SN_PROTECTION 39 #define SN_IRRITATION 40 #define SN_VULNERABILITY 41 #define SN_ENVELOPING 42 #define SN_FIRE 43 #define SN_SLAY_EVIL 44 #define SN_DRAGON_SLAYING 45 #define SN_EMPTY 46 #define SN_LOCKED 47 #define SN_POISON_NEEDLE 48 #define SN_GAS_TRAP 49 #define SN_EXPLOSION_DEVICE 50 #define SN_SUMMONING_RUNES 51 #define SN_MULTIPLE_TRAPS 52 #define SN_DISARMED 53 #define SN_UNLOCKED 54 #define SN_SLAY_ANIMAL 55 #define SN_ARRAY_SIZE 56 /* must be at end of this list */ /* defines for treasure type values (tval) */ #define TV_NEVER -1 /* used by find_range() for non-search */ #define TV_NOTHING 0 #define TV_MISC 1 #define TV_CHEST 2 /* min tval for wearable items, all items between TV_MIN_WEAR and TV_MAX_WEAR use the same flag bits, see the TR_* defines */ #define TV_MIN_WEAR 10 /* items tested for enchantments, i.e. the MAGIK inscription, see the enchanted() procedure */ #define TV_MIN_ENCHANT 10 #define TV_SLING_AMMO 10 #define TV_BOLT 11 #define TV_ARROW 12 #define TV_SPIKE 13 #define TV_LIGHT 15 #define TV_BOW 20 #define TV_HAFTED 21 #define TV_POLEARM 22 #define TV_SWORD 23 #define TV_DIGGING 25 #define TV_BOOTS 30 #define TV_GLOVES 31 #define TV_CLOAK 32 #define TV_HELM 33 #define TV_SHIELD 34 #define TV_HARD_ARMOR 35 #define TV_SOFT_ARMOR 36 /* max tval that uses the TR_* flags */ #define TV_MAX_ENCHANT 39 #define TV_AMULET 40 #define TV_RING 45 /* max tval for wearable items */ #define TV_MAX_WEAR 50 #define TV_STAFF 55 #define TV_WAND 65 #define TV_SCROLL1 70 #define TV_SCROLL2 71 #define TV_POTION1 75 #define TV_POTION2 76 #define TV_FLASK 77 #define TV_FOOD 80 #define TV_MAGIC_BOOK 90 #define TV_PRAYER_BOOK 91 /* objects with tval above this are never picked up by monsters */ #define TV_MAX_OBJECT 99 #define TV_GOLD 100 /* objects with higher tvals can not be picked up */ #define TV_MAX_PICK_UP 100 #define TV_INVIS_TRAP 101 /* objects between TV_MIN_VISIBLE and TV_MAX_VISIBLE are always visible, i.e. the cave fm flag is set when they are present */ #define TV_MIN_VISIBLE 102 #define TV_VIS_TRAP 102 #define TV_RUBBLE 103 /* following objects are never deleted when trying to create another one during level generation */ #define TV_MIN_DOORS 104 #define TV_OPEN_DOOR 104 #define TV_CLOSED_DOOR 105 #define TV_UP_STAIR 107 #define TV_DOWN_STAIR 108 #define TV_SECRET_DOOR 109 #define TV_STORE_DOOR 110 #define TV_MAX_VISIBLE 110 /* spell types used by get_flags(), breathe(), fire_bolt() and fire_ball() */ #define GF_MAGIC_MISSILE 0 #define GF_LIGHTNING 1 #define GF_POISON_GAS 2 #define GF_ACID 3 #define GF_FROST 4 #define GF_FIRE 5 #define GF_HOLY_ORB 6 /* Number of entries allowed in the scorefile. */ #define SCOREFILE_SIZE 1000 moria-5.6.debian.1/source/generate.c0000644000175000017500000010630511074756544015443 0ustar pjbpjb/* source/generate.c: initialize/create a dungeon or town level Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #if defined(USG) && !defined(VMS) && !defined(MAC) #if !defined(ATARIST_MWC) && !defined(AMIGA) #if !defined(__TURBOC__) #include #else #ifndef ATARIST_TC #include #endif #endif #endif #endif #if defined(MAC) #include #endif #ifdef ATARIST_TC #include #endif typedef struct coords { int x, y; } coords; #if defined(LINT_ARGS) static void correct_dir(int *, int * , int, int, int, int); static void rand_dir(int *,int *); static void blank_cave(void); static void fill_cave(int); static void place_boundary(void); static void place_streamer(int, int); static void place_open_door(int, int); static void place_broken_door(int, int); static void place_closed_door(int, int); static void place_locked_door(int, int); static void place_stuck_door(int, int); static void place_secret_door(int, int); static void place_door(int, int); static void place_up_stairs(int, int); static void place_down_stairs(int, int); static void place_stairs(int, int, int); static void vault_trap(int, int, int, int, int); static void vault_monster(int, int, int); static void build_room(int, int); static void build_type1(int, int); static void build_type2(int, int); static void build_type3(int, int); static void build_tunnel(int, int, int, int); static int next_to(int, int); static void try_door(int, int); static void new_spot(int16 *, int16 *); static void cave_gen(void); static void build_store(int, int, int); static void tlink(void); static void mlink(void); static void town_gen(void); #endif static coords doorstk[100]; static int doorindex; /* Always picks a correct direction */ static void correct_dir(rdir, cdir, y1, x1, y2, x2) int *rdir, *cdir; register int y1, x1, y2, x2; { if (y1 < y2) *rdir = 1; else if (y1 == y2) *rdir = 0; else *rdir = -1; if (x1 < x2) *cdir = 1; else if (x1 == x2) *cdir = 0; else *cdir = -1; if ((*rdir != 0) && (*cdir != 0)) { if (randint (2) == 1) *rdir = 0; else *cdir = 0; } } /* Chance of wandering direction */ static void rand_dir(rdir, cdir) int *rdir, *cdir; { register int tmp; tmp = randint(4); if (tmp < 3) { *cdir = 0; *rdir = -3 + (tmp << 1); /* tmp=1 -> *rdir=-1; tmp=2 -> *rdir=1 */ } else { *rdir = 0; *cdir = -7 + (tmp << 1); /* tmp=3 -> *cdir=-1; tmp=4 -> *cdir=1 */ } } /* Blanks out entire cave -RAK- */ static void blank_cave() { #ifndef USG bzero ((char *)&cave[0][0], sizeof (cave)); #else #ifdef MAC /* On the mac, cave is a pointer, so sizeof(cave) = 4! */ (void)memset((char *)&cave[0][0], 0, (long) sizeof(cave_type) * MAX_HEIGHT * MAX_WIDTH); #else (void)memset((char *)&cave[0][0], 0, sizeof (cave)); #endif #endif } /* Fills in empty spots with desired rock -RAK- */ /* Note: 9 is a temporary value. */ static void fill_cave(fval) register int fval; { register int i, j; register cave_type *c_ptr; /* no need to check the border of the cave */ for (i = cur_height - 2; i > 0; i--) { c_ptr = &cave[i][1]; for (j = cur_width - 2; j > 0; j--) { if ((c_ptr->fval == NULL_WALL) || (c_ptr->fval == TMP1_WALL) || (c_ptr->fval == TMP2_WALL)) c_ptr->fval = fval; c_ptr++; } } } #ifdef DEBUG #include #endif /* Places indestructible rock around edges of dungeon -RAK- */ static void place_boundary() { register int i; register cave_type *top_ptr, *bottom_ptr; cave_type (*left_ptr)[MAX_WIDTH]; cave_type (*right_ptr)[MAX_WIDTH]; /* put permanent wall on leftmost row and rightmost row */ left_ptr = (cave_type (*)[MAX_WIDTH]) &cave[0][0]; right_ptr = (cave_type (*)[MAX_WIDTH]) &cave[0][cur_width - 1]; for (i = 0; i < cur_height; i++) { #ifdef DEBUG assert ((cave_type *)left_ptr == &cave[i][0]); assert ((cave_type *)right_ptr == &cave[i][cur_width-1]); #endif ((cave_type *)left_ptr)->fval = BOUNDARY_WALL; left_ptr++; ((cave_type *)right_ptr)->fval = BOUNDARY_WALL; right_ptr++; } /* put permanent wall on top row and bottom row */ top_ptr = &cave[0][0]; bottom_ptr = &cave[cur_height - 1][0]; for (i = 0; i < cur_width; i++) { #ifdef DEBUG assert (top_ptr == &cave[0][i]); assert (bottom_ptr == &cave[cur_height - 1][i]); #endif top_ptr->fval = BOUNDARY_WALL; top_ptr++; bottom_ptr->fval = BOUNDARY_WALL; bottom_ptr++; } } /* Places "streamers" of rock through dungeon -RAK- */ static void place_streamer(fval, treas_chance) int fval; int treas_chance; { register int i, tx, ty; int y, x, t1, t2, dir; register cave_type *c_ptr; /* Choose starting point and direction */ y = (cur_height / 2) + 11 - randint(23); x = (cur_width / 2) + 16 - randint(33); dir = randint(8); /* Number 1-4, 6-9 */ if (dir > 4) dir = dir + 1; /* Place streamer into dungeon */ t1 = 2*DUN_STR_RNG + 1; /* Constants */ t2 = DUN_STR_RNG + 1; do { for (i = 0; i < DUN_STR_DEN; i++) { ty = y + randint(t1) - t2; tx = x + randint(t1) - t2; if (in_bounds(ty, tx)) { c_ptr = &cave[ty][tx]; if (c_ptr->fval == GRANITE_WALL) { c_ptr->fval = fval; if (randint(treas_chance) == 1) place_gold(ty, tx); } } } } while (mmove(dir, &y, &x)); } static void place_open_door(y, x) int y, x; { register int cur_pos; register cave_type *cave_ptr; cur_pos = popt(); cave_ptr = &cave[y][x]; cave_ptr->tptr = cur_pos; invcopy(&t_list[cur_pos], OBJ_OPEN_DOOR); cave_ptr->fval = CORR_FLOOR; } static void place_broken_door(y, x) int y, x; { register int cur_pos; register cave_type *cave_ptr; cur_pos = popt(); cave_ptr = &cave[y][x]; cave_ptr->tptr = cur_pos; invcopy(&t_list[cur_pos], OBJ_OPEN_DOOR); cave_ptr->fval = CORR_FLOOR; t_list[cur_pos].p1 = 1; } static void place_closed_door(y, x) int y, x; { register int cur_pos; register cave_type *cave_ptr; cur_pos = popt(); cave_ptr = &cave[y][x]; cave_ptr->tptr = cur_pos; invcopy(&t_list[cur_pos], OBJ_CLOSED_DOOR); cave_ptr->fval = BLOCKED_FLOOR; } static void place_locked_door(y, x) int y, x; { register int cur_pos; register cave_type *cave_ptr; cur_pos = popt(); cave_ptr = &cave[y][x]; cave_ptr->tptr = cur_pos; invcopy(&t_list[cur_pos], OBJ_CLOSED_DOOR); cave_ptr->fval = BLOCKED_FLOOR; t_list[cur_pos].p1 = randint(10) + 10; } static void place_stuck_door(y, x) int y, x; { register int cur_pos; register cave_type *cave_ptr; cur_pos = popt(); cave_ptr = &cave[y][x]; cave_ptr->tptr = cur_pos; invcopy(&t_list[cur_pos], OBJ_CLOSED_DOOR); cave_ptr->fval = BLOCKED_FLOOR; t_list[cur_pos].p1 = -randint(10) - 10; } static void place_secret_door(y, x) int y, x; { register int cur_pos; register cave_type *cave_ptr; cur_pos = popt(); cave_ptr = &cave[y][x]; cave_ptr->tptr = cur_pos; invcopy(&t_list[cur_pos], OBJ_SECRET_DOOR); cave_ptr->fval = BLOCKED_FLOOR; } static void place_door(y, x) int y, x; { register int tmp; tmp = randint(3); if (tmp == 1) { if (randint(4) == 1) place_broken_door(y, x); else place_open_door(y, x); } else if (tmp == 2) { tmp = randint(12); if (tmp > 3) place_closed_door(y, x); else if (tmp == 3) place_stuck_door(y, x); else place_locked_door(y, x); } else place_secret_door(y, x); } /* Place an up staircase at given y, x -RAK- */ static void place_up_stairs(y, x) int y, x; { register int cur_pos; register cave_type *cave_ptr; cave_ptr = &cave[y][x]; if (cave_ptr->tptr != 0) (void) delete_object(y, x); cur_pos = popt(); cave_ptr->tptr = cur_pos; invcopy(&t_list[cur_pos], OBJ_UP_STAIR); } /* Place a down staircase at given y, x -RAK- */ static void place_down_stairs(y, x) int y, x; { register int cur_pos; register cave_type *cave_ptr; cave_ptr = &cave[y][x]; if (cave_ptr->tptr != 0) (void) delete_object(y, x); cur_pos = popt(); cave_ptr->tptr = cur_pos; invcopy(&t_list[cur_pos], OBJ_DOWN_STAIR); } /* Places a staircase 1=up, 2=down -RAK- */ static void place_stairs(typ, num, walls) int typ, num, walls; { register cave_type *cave_ptr; int i, j, flag; register int y1, x1, y2, x2; for (i = 0; i < num; i++) { flag = FALSE; do { j = 0; do { /* Note: don't let y1/x1 be zero, and don't let y2/x2 be equal to cur_height-1/cur_width-1, these values are always BOUNDARY_ROCK. */ y1 = randint(cur_height - 14); x1 = randint(cur_width - 14); y2 = y1 + 12; x2 = x1 + 12; do { do { cave_ptr = &cave[y1][x1]; if (cave_ptr->fval <= MAX_OPEN_SPACE && (cave_ptr->tptr == 0) && (next_to_walls(y1, x1) >= walls)) { flag = TRUE; if (typ == 1) place_up_stairs(y1, x1); else place_down_stairs(y1, x1); } x1++; } while ((x1 != x2) && (!flag)); x1 = x2 - 12; y1++; } while ((y1 != y2) && (!flag)); j++; } while ((!flag) && (j <= 30)); walls--; } while (!flag); } } /* Place a trap with a given displacement of point -RAK- */ static void vault_trap(y, x, yd, xd, num) int y, x, yd, xd, num; { register int count, y1, x1; int i, flag; register cave_type *c_ptr; for (i = 0; i < num; i++) { flag = FALSE; count = 0; do { y1 = y - yd - 1 + randint(2*yd+1); x1 = x - xd - 1 + randint(2*xd+1); c_ptr = &cave[y1][x1]; if ((c_ptr->fval != NULL_WALL) && (c_ptr->fval <= MAX_CAVE_FLOOR) && (c_ptr->tptr == 0)) { place_trap(y1, x1, randint(MAX_TRAP)-1); flag = TRUE; } count++; } while ((!flag) && (count <= 5)); } } /* Place a trap with a given displacement of point -RAK- */ static void vault_monster(y, x, num) int y, x, num; { register int i; int y1, x1; for (i = 0; i < num; i++) { y1 = y; x1 = x; (void) summon_monster(&y1, &x1, TRUE); } } /* Builds a room at a row, column coordinate -RAK- */ static void build_room(yval, xval) int yval, xval; { register int i, j, y_depth, x_right; int y_height, x_left; int8u floor; register cave_type *c_ptr, *d_ptr; if (dun_level <= randint(25)) floor = LIGHT_FLOOR; /* Floor with light */ else floor = DARK_FLOOR; /* Dark floor */ y_height = yval - randint(4); y_depth = yval + randint(3); x_left = xval - randint(11); x_right = xval + randint(11); /* the x dim of rooms tends to be much larger than the y dim, so don't bother rewriting the y loop */ for (i = y_height; i <= y_depth; i++) { c_ptr = &cave[i][x_left]; for (j = x_left; j <= x_right; j++) { c_ptr->fval = floor; c_ptr->lr = TRUE; c_ptr++; } } for (i = (y_height - 1); i <= (y_depth + 1); i++) { c_ptr = &cave[i][x_left-1]; c_ptr->fval = GRANITE_WALL; c_ptr->lr = TRUE; c_ptr = &cave[i][x_right+1]; c_ptr->fval = GRANITE_WALL; c_ptr->lr = TRUE; } c_ptr = &cave[y_height - 1][x_left]; d_ptr = &cave[y_depth + 1][x_left]; for (i = x_left; i <= x_right; i++) { c_ptr->fval = GRANITE_WALL; c_ptr->lr = TRUE; c_ptr++; d_ptr->fval = GRANITE_WALL; d_ptr->lr = TRUE; d_ptr++; } } /* Builds a room at a row, column coordinate -RAK- */ /* Type 1 unusual rooms are several overlapping rectangular ones */ static void build_type1(yval, xval) int yval, xval; { int y_height, y_depth; int x_left, x_right, limit; register int i0, i, j; int8u floor; register cave_type *c_ptr, *d_ptr; if (dun_level <= randint(25)) floor = LIGHT_FLOOR; /* Floor with light */ else floor = DARK_FLOOR; /* Dark floor */ limit = 1 + randint(2); for (i0 = 0; i0 < limit; i0++) { y_height = yval - randint(4); y_depth = yval + randint(3); x_left = xval - randint(11); x_right = xval + randint(11); /* the x dim of rooms tends to be much larger than the y dim, so don't bother rewriting the y loop */ for (i = y_height; i <= y_depth; i++) { c_ptr = &cave[i][x_left]; for (j = x_left; j <= x_right; j++) { c_ptr->fval = floor; c_ptr->lr = TRUE; c_ptr++; } } for (i = (y_height - 1); i <= (y_depth + 1); i++) { c_ptr = &cave[i][x_left-1]; if (c_ptr->fval != floor) { c_ptr->fval = GRANITE_WALL; c_ptr->lr = TRUE; } c_ptr = &cave[i][x_right+1]; if (c_ptr->fval != floor) { c_ptr->fval = GRANITE_WALL; c_ptr->lr = TRUE; } } c_ptr = &cave[y_height - 1][x_left]; d_ptr = &cave[y_depth + 1][x_left]; for (i = x_left; i <= x_right; i++) { if (c_ptr->fval != floor) { c_ptr->fval = GRANITE_WALL; c_ptr->lr = TRUE; } c_ptr++; if (d_ptr->fval != floor) { d_ptr->fval = GRANITE_WALL; d_ptr->lr = TRUE; } d_ptr++; } } } /* Builds an unusual room at a row, column coordinate -RAK- */ /* Type 2 unusual rooms all have an inner room: */ /* 1 - Just an inner room with one door */ /* 2 - An inner room within an inner room */ /* 3 - An inner room with pillar(s) */ /* 4 - Inner room has a maze */ /* 5 - A set of four inner rooms */ static void build_type2(yval, xval) int yval, xval; { register int i, j, y_height, x_left; int y_depth, x_right, tmp; int8u floor; register cave_type *c_ptr, *d_ptr; if (dun_level <= randint(25)) floor = LIGHT_FLOOR; /* Floor with light */ else floor = DARK_FLOOR; /* Dark floor */ y_height = yval - 4; y_depth = yval + 4; x_left = xval - 11; x_right = xval + 11; /* the x dim of rooms tends to be much larger than the y dim, so don't bother rewriting the y loop */ for (i = y_height; i <= y_depth; i++) { c_ptr = &cave[i][x_left]; for (j = x_left; j <= x_right; j++) { c_ptr->fval = floor; c_ptr->lr = TRUE; c_ptr++; } } for (i = (y_height - 1); i <= (y_depth + 1); i++) { c_ptr = &cave[i][x_left-1]; c_ptr->fval = GRANITE_WALL; c_ptr->lr = TRUE; c_ptr = &cave[i][x_right+1]; c_ptr->fval = GRANITE_WALL; c_ptr->lr = TRUE; } c_ptr = &cave[y_height - 1][x_left]; d_ptr = &cave[y_depth + 1][x_left]; for (i = x_left; i <= x_right; i++) { c_ptr->fval = GRANITE_WALL; c_ptr->lr = TRUE; c_ptr++; d_ptr->fval = GRANITE_WALL; d_ptr->lr = TRUE; d_ptr++; } /* The inner room */ y_height = y_height + 2; y_depth = y_depth - 2; x_left = x_left + 2; x_right = x_right - 2; for (i = (y_height - 1); i <= (y_depth + 1); i++) { cave[i][x_left-1].fval = TMP1_WALL; cave[i][x_right+1].fval = TMP1_WALL; } c_ptr = &cave[y_height-1][x_left]; d_ptr = &cave[y_depth+1][x_left]; for (i = x_left; i <= x_right; i++) { c_ptr->fval = TMP1_WALL; c_ptr++; d_ptr->fval = TMP1_WALL; d_ptr++; } /* Inner room variations */ switch(randint(5)) { case 1: /* Just an inner room. */ tmp = randint(4); if (tmp < 3) { /* Place a door */ if (tmp == 1) place_secret_door(y_height-1, xval); else place_secret_door(y_depth+1, xval); } else { if (tmp == 3) place_secret_door(yval, x_left-1); else place_secret_door(yval, x_right+1); } vault_monster(yval, xval, 1); break; case 2: /* Treasure Vault */ tmp = randint(4); if (tmp < 3) { /* Place a door */ if (tmp == 1) place_secret_door(y_height-1, xval); else place_secret_door(y_depth+1, xval); } else { if (tmp == 3) place_secret_door(yval, x_left-1); else place_secret_door(yval, x_right+1); } for (i = yval-1; i <= yval+1; i++) { cave[i][xval-1].fval = TMP1_WALL; cave[i][xval+1].fval = TMP1_WALL; } cave[yval-1][xval].fval = TMP1_WALL; cave[yval+1][xval].fval = TMP1_WALL; tmp = randint(4); /* Place a door */ if (tmp < 3) place_locked_door(yval-3+(tmp<<1), xval); /* 1 -> yval-1; 2 -> yval+1*/ else place_locked_door(yval, xval-7+(tmp<<1)); /* Place an object in the treasure vault */ tmp = randint(10); if (tmp > 2) place_object(yval, xval, FALSE); else if (tmp == 2) place_down_stairs(yval, xval); else place_up_stairs(yval, xval); /* Guard the treasure well */ vault_monster(yval, xval, 2+randint(3)); /* If the monsters don't get 'em. */ vault_trap(yval, xval, 4, 10, 2+randint(3)); break; case 3: /* Inner pillar(s). */ tmp = randint(4); if (tmp < 3) { /* Place a door */ if (tmp == 1) place_secret_door(y_height-1, xval); else place_secret_door(y_depth+1, xval); } else { if (tmp == 3) place_secret_door(yval, x_left-1); else place_secret_door(yval, x_right+1); } for (i = yval-1; i <= yval+1; i++) { c_ptr = &cave[i][xval-1]; for (j = xval-1; j <= xval+1; j++) { c_ptr->fval = TMP1_WALL; c_ptr++; } } if (randint(2) == 1) { tmp = randint(2); for (i = yval-1; i <= yval+1; i++) { c_ptr = &cave[i][xval-5-tmp]; for (j = xval-5-tmp; j <= xval-3-tmp; j++) { c_ptr->fval = TMP1_WALL; c_ptr++; } } for (i = yval-1; i <= yval+1; i++) { c_ptr = &cave[i][xval+3+tmp]; for (j = xval+3+tmp; j <= xval+5+tmp; j++) { c_ptr->fval = TMP1_WALL; c_ptr++; } } } if (randint(3) == 1) /* Inner rooms */ { c_ptr = &cave[yval-1][xval-5]; d_ptr = &cave[yval+1][xval-5]; for (i = xval-5; i <= xval+5; i++) { c_ptr->fval = TMP1_WALL; c_ptr++; d_ptr->fval = TMP1_WALL; d_ptr++; } cave[yval][xval-5].fval = TMP1_WALL; cave[yval][xval+5].fval = TMP1_WALL; place_secret_door(yval-3+(randint(2)<<1), xval-3); place_secret_door(yval-3+(randint(2)<<1), xval+3); if (randint(3) == 1) place_object(yval, xval-2, FALSE); if (randint(3) == 1) place_object(yval, xval+2, FALSE); vault_monster(yval, xval-2, randint(2)); vault_monster(yval, xval+2, randint(2)); } break; case 4: /* Maze inside. */ tmp = randint(4); if (tmp < 3) { /* Place a door */ if (tmp == 1) place_secret_door(y_height-1, xval); else place_secret_door(y_depth+1, xval); } else { if (tmp == 3) place_secret_door(yval, x_left-1); else place_secret_door(yval, x_right+1); } for (i = y_height; i <= y_depth; i++) for (j = x_left; j <= x_right; j++) if (0x1 & (j+i)) cave[i][j].fval = TMP1_WALL; /* Monsters just love mazes. */ vault_monster(yval, xval-5, randint(3)); vault_monster(yval, xval+5, randint(3)); /* Traps make them entertaining. */ vault_trap(yval, xval-3, 2, 8, randint(3)); vault_trap(yval, xval+3, 2, 8, randint(3)); /* Mazes should have some treasure too.. */ for (i = 0; i < 3; i++) random_object(yval, xval, 1); break; case 5: /* Four small rooms. */ for (i = y_height; i <= y_depth; i++) cave[i][xval].fval = TMP1_WALL; c_ptr = &cave[yval][x_left]; for (i = x_left; i <= x_right; i++) { c_ptr->fval = TMP1_WALL; c_ptr++; } if (randint(2) == 1) { i = randint(10); place_secret_door(y_height-1, xval-i); place_secret_door(y_height-1, xval+i); place_secret_door(y_depth+1, xval-i); place_secret_door(y_depth+1, xval+i); } else { i = randint(3); place_secret_door(yval+i, x_left-1); place_secret_door(yval-i, x_left-1); place_secret_door(yval+i, x_right+1); place_secret_door(yval-i, x_right+1); } /* Treasure in each one. */ random_object(yval, xval, 2+randint(2)); /* Gotta have some monsters. */ vault_monster(yval+2, xval-4, randint(2)); vault_monster(yval+2, xval+4, randint(2)); vault_monster(yval-2, xval-4, randint(2)); vault_monster(yval-2, xval+4, randint(2)); break; } } /* Builds a room at a row, column coordinate -RAK- */ /* Type 3 unusual rooms are cross shaped */ static void build_type3(yval, xval) int yval, xval; { int y_height, y_depth; int x_left, x_right; register int tmp, i, j; int8u floor; register cave_type *c_ptr; if (dun_level <= randint(25)) floor = LIGHT_FLOOR; /* Floor with light */ else floor = DARK_FLOOR; /* Dark floor */ tmp = 2 + randint(2); y_height = yval - tmp; y_depth = yval + tmp; x_left = xval - 1; x_right = xval + 1; for (i = y_height; i <= y_depth; i++) for (j = x_left; j <= x_right; j++) { c_ptr = &cave[i][j]; c_ptr->fval = floor; c_ptr->lr = TRUE; } for (i = (y_height - 1); i <= (y_depth + 1); i++) { c_ptr = &cave[i][x_left-1]; c_ptr->fval = GRANITE_WALL; c_ptr->lr = TRUE; c_ptr = &cave[i][x_right+1]; c_ptr->fval = GRANITE_WALL; c_ptr->lr = TRUE; } for (i = x_left; i <= x_right; i++) { c_ptr = &cave[y_height-1][i]; c_ptr->fval = GRANITE_WALL; c_ptr->lr = TRUE; c_ptr = &cave[y_depth+1][i]; c_ptr->fval = GRANITE_WALL; c_ptr->lr = TRUE; } tmp = 2 + randint(9); y_height = yval - 1; y_depth = yval + 1; x_left = xval - tmp; x_right = xval + tmp; for (i = y_height; i <= y_depth; i++) for (j = x_left; j <= x_right; j++) { c_ptr = &cave[i][j]; c_ptr->fval = floor; c_ptr->lr = TRUE; } for (i = (y_height - 1); i <= (y_depth + 1); i++) { c_ptr = &cave[i][x_left-1]; if (c_ptr->fval != floor) { c_ptr->fval = GRANITE_WALL; c_ptr->lr = TRUE; } c_ptr = &cave[i][x_right+1]; if (c_ptr->fval != floor) { c_ptr->fval = GRANITE_WALL; c_ptr->lr = TRUE; } } for (i = x_left; i <= x_right; i++) { c_ptr = &cave[y_height-1][i]; if (c_ptr->fval != floor) { c_ptr->fval = GRANITE_WALL; c_ptr->lr = TRUE; } c_ptr = &cave[y_depth+1][i]; if (c_ptr->fval != floor) { c_ptr->fval = GRANITE_WALL; c_ptr->lr = TRUE; } } /* Special features. */ switch(randint(4)) { case 1: /* Large middle pillar */ for (i = yval-1; i <= yval+1; i++) { c_ptr = &cave[i][xval-1]; for (j = xval-1; j <= xval+1; j++) { c_ptr->fval = TMP1_WALL; c_ptr++; } } break; case 2: /* Inner treasure vault */ for (i = yval-1; i <= yval+1; i++) { cave[i][xval-1].fval = TMP1_WALL; cave[i][xval+1].fval = TMP1_WALL; } cave[yval-1][xval].fval = TMP1_WALL; cave[yval+1][xval].fval = TMP1_WALL; tmp = randint(4); /* Place a door */ if (tmp < 3) place_secret_door(yval-3+(tmp<<1), xval); else place_secret_door(yval, xval-7+(tmp<<1)); /* Place a treasure in the vault */ place_object(yval, xval, FALSE); /* Let's guard the treasure well. */ vault_monster(yval, xval, 2+randint(2)); /* Traps naturally */ vault_trap(yval, xval, 4, 4, 1+randint(3)); break; case 3: if (randint(3) == 1) { cave[yval-1][xval-2].fval = TMP1_WALL; cave[yval+1][xval-2].fval = TMP1_WALL; cave[yval-1][xval+2].fval = TMP1_WALL; cave[yval+1][xval+2].fval = TMP1_WALL; cave[yval-2][xval-1].fval = TMP1_WALL; cave[yval-2][xval+1].fval = TMP1_WALL; cave[yval+2][xval-1].fval = TMP1_WALL; cave[yval+2][xval+1].fval = TMP1_WALL; if (randint(3) == 1) { place_secret_door(yval, xval-2); place_secret_door(yval, xval+2); place_secret_door(yval-2, xval); place_secret_door(yval+2, xval); } } else if (randint(3) == 1) { cave[yval][xval].fval = TMP1_WALL; cave[yval-1][xval].fval = TMP1_WALL; cave[yval+1][xval].fval = TMP1_WALL; cave[yval][xval-1].fval = TMP1_WALL; cave[yval][xval+1].fval = TMP1_WALL; } else if (randint(3) == 1) cave[yval][xval].fval = TMP1_WALL; break; case 4: break; } } /* Constructs a tunnel between two points */ static void build_tunnel(row1, col1, row2, col2) int row1, col1, row2, col2; { register int tmp_row, tmp_col, i, j; register cave_type *c_ptr; cave_type *d_ptr; coords tunstk[1000], wallstk[1000]; coords *tun_ptr; int row_dir, col_dir, tunindex, wallindex; int stop_flag, door_flag, main_loop_count; int start_row, start_col; /* Main procedure for Tunnel */ /* Note: 9 is a temporary value */ stop_flag = FALSE; door_flag = FALSE; tunindex = 0; wallindex = 0; main_loop_count = 0; start_row = row1; start_col = col1; correct_dir(&row_dir, &col_dir, row1, col1, row2, col2); do { /* prevent infinite loops, just in case */ main_loop_count++; if (main_loop_count > 2000) stop_flag = TRUE; if (randint(100) > DUN_TUN_CHG) { if (randint(DUN_TUN_RND) == 1) rand_dir(&row_dir, &col_dir); else correct_dir(&row_dir, &col_dir, row1, col1, row2, col2); } tmp_row = row1 + row_dir; tmp_col = col1 + col_dir; while (!in_bounds(tmp_row, tmp_col)) { if (randint(DUN_TUN_RND) == 1) rand_dir(&row_dir, &col_dir); else correct_dir(&row_dir, &col_dir, row1, col1, row2, col2); tmp_row = row1 + row_dir; tmp_col = col1 + col_dir; } c_ptr = &cave[tmp_row][tmp_col]; if (c_ptr->fval == NULL_WALL) { row1 = tmp_row; col1 = tmp_col; if (tunindex < 1000) { tunstk[tunindex].y = row1; tunstk[tunindex].x = col1; tunindex++; } door_flag = FALSE; } else if (c_ptr->fval == TMP2_WALL) /* do nothing */ ; else if (c_ptr->fval == GRANITE_WALL) { row1 = tmp_row; col1 = tmp_col; if (wallindex < 1000) { wallstk[wallindex].y = row1; wallstk[wallindex].x = col1; wallindex++; } for (i = row1-1; i <= row1+1; i++) for (j = col1-1; j <= col1+1; j++) if (in_bounds(i, j)) { d_ptr = &cave[i][j]; /* values 11 and 12 are impossible here, place_streamer is never run before build_tunnel */ if (d_ptr->fval == GRANITE_WALL) d_ptr->fval = TMP2_WALL; } } else if (c_ptr->fval == CORR_FLOOR || c_ptr->fval == BLOCKED_FLOOR) { row1 = tmp_row; col1 = tmp_col; if (!door_flag) { if (doorindex < 100) { doorstk[doorindex].y = row1; doorstk[doorindex].x = col1; doorindex++; } door_flag = TRUE; } if (randint(100) > DUN_TUN_CON) { /* make sure that tunnel has gone a reasonable distance before stopping it, this helps prevent isolated rooms */ tmp_row = row1 - start_row; if (tmp_row < 0) tmp_row = -tmp_row; tmp_col = col1 - start_col; if (tmp_col < 0) tmp_col = -tmp_col; if (tmp_row > 10 || tmp_col > 10) stop_flag = TRUE; } } else /* c_ptr->fval != NULL, TMP2, GRANITE, CORR */ { row1 = tmp_row; col1 = tmp_col; } } while (((row1 != row2) || (col1 != col2)) && (!stop_flag)); tun_ptr = &tunstk[0]; for (i = 0; i < tunindex; i++) { d_ptr = &cave[tun_ptr->y][tun_ptr->x]; d_ptr->fval = CORR_FLOOR; tun_ptr++; } for (i = 0; i < wallindex; i++) { c_ptr = &cave[wallstk[i].y][wallstk[i].x]; if (c_ptr->fval == TMP2_WALL) { if (randint(100) < DUN_TUN_PEN) place_door(wallstk[i].y, wallstk[i].x); else { /* these have to be doorways to rooms */ c_ptr->fval = CORR_FLOOR; } } } } static int next_to(y, x) register int y, x; { register int next; if (next_to_corr(y, x) > 2) if ((cave[y-1][x].fval >= MIN_CAVE_WALL) && (cave[y+1][x].fval >= MIN_CAVE_WALL)) next = TRUE; else if ((cave[y][x-1].fval >= MIN_CAVE_WALL) && (cave[y][x+1].fval >= MIN_CAVE_WALL)) next = TRUE; else next = FALSE; else next = FALSE; return(next); } /* Places door at y, x position if at least 2 walls found */ static void try_door(y, x) register int y, x; { if ((cave[y][x].fval == CORR_FLOOR) && (randint(100) > DUN_TUN_JCT) && next_to(y, x)) place_door(y, x); } /* Returns random co-ordinates -RAK- */ static void new_spot(y, x) int16 *y, *x; { register int i, j; register cave_type *c_ptr; do { i = randint(cur_height - 2); j = randint(cur_width - 2); c_ptr = &cave[i][j]; } while (c_ptr->fval >= MIN_CLOSED_SPACE || (c_ptr->cptr != 0) || (c_ptr->tptr != 0)); *y = i; *x = j; } /* Cave logic flow for generation of new dungeon */ static void cave_gen() { struct spot_type { int endx; int endy; }; int room_map[20][20]; register int i, j, k; int y1, x1, y2, x2, pick1, pick2, tmp; int row_rooms, col_rooms, alloc_level; int16 yloc[400], xloc[400]; row_rooms = 2*(cur_height/SCREEN_HEIGHT); col_rooms = 2*(cur_width /SCREEN_WIDTH); for (i = 0; i < row_rooms; i++) for (j = 0; j < col_rooms; j++) room_map[i][j] = FALSE; k = randnor(DUN_ROO_MEA, 2); for (i = 0; i < k; i++) room_map[randint(row_rooms)-1][randint(col_rooms)-1] = TRUE; k = 0; for (i = 0; i < row_rooms; i++) for (j = 0; j < col_rooms; j++) if (room_map[i][j] == TRUE) { yloc[k] = i * (SCREEN_HEIGHT >> 1) + QUART_HEIGHT; xloc[k] = j * (SCREEN_WIDTH >> 1) + QUART_WIDTH; if (dun_level > randint(DUN_UNUSUAL)) { tmp = randint(3); if (tmp == 1) build_type1(yloc[k], xloc[k]); else if (tmp == 2) build_type2(yloc[k], xloc[k]); else build_type3(yloc[k], xloc[k]); } else build_room(yloc[k], xloc[k]); k++; #ifdef MAC SystemTask (); #endif } for (i = 0; i < k; i++) { pick1 = randint(k) - 1; pick2 = randint(k) - 1; y1 = yloc[pick1]; x1 = xloc[pick1]; yloc[pick1] = yloc[pick2]; xloc[pick1] = xloc[pick2]; yloc[pick2] = y1; xloc[pick2] = x1; } doorindex = 0; /* move zero entry to k, so that can call build_tunnel all k times */ yloc[k] = yloc[0]; xloc[k] = xloc[0]; for (i = 0; i < k; i++) { y1 = yloc[i]; x1 = xloc[i]; y2 = yloc[i+1]; x2 = xloc[i+1]; build_tunnel(y2, x2, y1, x1); } #ifdef MAC SystemTask (); #endif fill_cave(GRANITE_WALL); for (i = 0; i < DUN_STR_MAG; i++) place_streamer(MAGMA_WALL, DUN_STR_MC); for (i = 0; i < DUN_STR_QUA; i++) place_streamer(QUARTZ_WALL, DUN_STR_QC); place_boundary(); /* Place intersection doors */ for (i = 0; i < doorindex; i++) { try_door(doorstk[i].y, doorstk[i].x-1); try_door(doorstk[i].y, doorstk[i].x+1); try_door(doorstk[i].y-1, doorstk[i].x); try_door(doorstk[i].y+1, doorstk[i].x); } #ifdef MAC SystemTask (); #endif alloc_level = (dun_level/3); if (alloc_level < 2) alloc_level = 2; else if (alloc_level > 10) alloc_level = 10; place_stairs(2, randint(2)+2, 3); place_stairs(1, randint(2), 3); /* Set up the character co-ords, used by alloc_monster, place_win_monster */ new_spot(&char_row, &char_col); alloc_monster((randint(8)+MIN_MALLOC_LEVEL+alloc_level), 0, TRUE); alloc_object(set_corr, 3, randint(alloc_level)); alloc_object(set_room, 5, randnor(TREAS_ROOM_ALLOC, 3)); alloc_object(set_floor, 5, randnor(TREAS_ANY_ALLOC, 3)); alloc_object(set_floor, 4, randnor(TREAS_GOLD_ALLOC, 3)); alloc_object(set_floor, 1, randint(alloc_level)); if (dun_level >= WIN_MON_APPEAR) place_win_monster(); } /* Builds a store at a row, column coordinate */ static void build_store(store_num, y, x) int store_num, y, x; { int yval, y_height, y_depth; int xval, x_left, x_right; register int i, j; int cur_pos, tmp; register cave_type *c_ptr; yval = y*10 + 5; xval = x*16 + 16; y_height = yval - randint(3); y_depth = yval + randint(4); x_left = xval - randint(6); x_right = xval + randint(6); for (i = y_height; i <= y_depth; i++) for (j = x_left; j <= x_right; j++) cave[i][j].fval = BOUNDARY_WALL; tmp = randint(4); if (tmp < 3) { i = randint(y_depth-y_height) + y_height - 1; if (tmp == 1) j = x_left; else j = x_right; } else { j = randint(x_right-x_left) + x_left - 1; if (tmp == 3) i = y_depth; else i = y_height; } c_ptr = &cave[i][j]; c_ptr->fval = CORR_FLOOR; cur_pos = popt(); c_ptr->tptr = cur_pos; invcopy(&t_list[cur_pos], OBJ_STORE_DOOR + store_num); } /* Link all free space in treasure list together */ static void tlink() { register int i; for (i = 0; i < MAX_TALLOC; i++) invcopy(&t_list[i], OBJ_NOTHING); tcptr = MIN_TRIX; } /* Link all free space in monster list together */ static void mlink() { register int i; for (i = 0; i < MAX_MALLOC; i++) m_list[i] = blank_monster; mfptr = MIN_MONIX; } /* Town logic flow for generation of new town */ static void town_gen() { register int i, j, l, m; register cave_type *c_ptr; int rooms[6], k; set_seed(town_seed); for (i = 0; i < 6; i++) rooms[i] = i; l = 6; for (i = 0; i < 2; i++) for (j = 0; j < 3; j++) { k = randint(l) - 1; build_store(rooms[k], i, j); for (m = k; m < l-1; m++) rooms[m] = rooms[m+1]; l--; } fill_cave(DARK_FLOOR); /* make stairs before reset_seed, so that they don't move around */ place_boundary(); place_stairs(2, 1, 0); reset_seed(); /* Set up the character co-ords, used by alloc_monster below */ new_spot(&char_row, &char_col); if (0x1 & (turn / 5000)) { /* Night */ for (i = 0; i < cur_height; i++) { c_ptr = &cave[i][0]; for (j = 0; j < cur_width; j++) { if (c_ptr->fval != DARK_FLOOR) c_ptr->pl = TRUE; c_ptr++; } #ifdef MAC SystemTask (); #endif } alloc_monster(MIN_MALLOC_TN, 3, TRUE); } else { /* Day */ for (i = 0; i < cur_height; i++) { c_ptr = &cave[i][0]; for (j = 0; j < cur_width; j++) { c_ptr->pl = TRUE; c_ptr++; } #ifdef MAC SystemTask (); #endif } alloc_monster(MIN_MALLOC_TD, 3, TRUE); } store_maint(); } /* Generates a random dungeon level -RAK- */ void generate_cave() { panel_row_min = 0; panel_row_max = 0; panel_col_min = 0; panel_col_max = 0; char_row = -1; char_col = -1; #ifdef MAC macbeginwait (); #endif tlink(); mlink(); blank_cave(); if (dun_level == 0) { cur_height = SCREEN_HEIGHT; cur_width = SCREEN_WIDTH; max_panel_rows = (cur_height/SCREEN_HEIGHT)*2 - 2; max_panel_cols = (cur_width /SCREEN_WIDTH )*2 - 2; panel_row = max_panel_rows; panel_col = max_panel_cols; town_gen(); } else { cur_height = MAX_HEIGHT; cur_width = MAX_WIDTH; max_panel_rows = (cur_height/SCREEN_HEIGHT)*2 - 2; max_panel_cols = (cur_width /SCREEN_WIDTH )*2 - 2; panel_row = max_panel_rows; panel_col = max_panel_cols; cave_gen(); } #ifdef MAC macendwait (); #endif } moria-5.6.debian.1/source/death.c0000644000175000017500000006115311074756544014737 0ustar pjbpjb/* source/death.c: code executed when player dies Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ /* Must read this before externs.h, as some global declarations use FILE. */ #include #include "config.h" #include "constant.h" #include "types.h" #ifdef Pyramid #include #else #include #endif #include #ifndef USG /* only needed for Berkeley UNIX */ #include #include #include #else #ifdef SYS_V /* XENIX and SYSV seem to need this */ #include #endif #endif #ifdef MSDOS #include #else #if !defined(ATARIST_MWC) && !defined(MAC) && !defined(AMIGA) #if !defined(ATARIST_TC) #ifndef VMS #include #else #include #endif #endif #endif #endif #ifdef VMS unsigned int getuid(), getgid(); #else #ifdef unix #ifdef USG unsigned short getuid(), getgid(); #else #ifndef SECURE #ifdef BSD4_3 uid_t getuid(), getgid(); #else /* other BSD versions */ int getuid(), getgid(); #endif #endif #endif #endif #endif #ifdef USG #ifndef ATARIST_MWC #include #ifndef VMS #ifndef ATARIST_TC #include #endif #endif #endif #else #include #endif /* This must be included after fcntl.h, which has a prototype for `open' on some systems. Otherwise, the `open' prototype conflicts with the `topen' declaration. */ #include "externs.h" #ifndef BSD4_3 #ifndef ATARIST_TC long lseek(); #endif /* ATARTIST_TC */ #else off_t lseek(); #endif #if defined(USG) || defined(VMS) || defined(atarist) #ifndef L_SET #define L_SET 0 #endif #ifndef L_INCR #define L_INCR 1 #endif #endif #ifndef VMS #ifndef MAC #if defined(ultrix) || defined(USG) void exit (); #endif #endif #endif #if defined(LINT_ARGS) static void date(char *); static char *center_string(char *, char *); static void print_tomb(void); static void kingly(void); #endif #ifdef ATARIST_TC /* Include this to get prototypes for standard library functions. */ #include #endif #ifndef VMS #ifndef MAC #if !defined(ATARIST_MWC) && !defined(AMIGA) long time(); #endif #endif #endif static void date(day) char *day; { register char *tmp; #ifdef MAC time_t clockvar; #else long clockvar; #endif #ifdef MAC clockvar = time((time_t *) 0); #else clockvar = time((long *) 0); #endif tmp = ctime(&clockvar); tmp[10] = '\0'; (void) strcpy(day, tmp); } /* Centers a string within a 31 character string -JWT- */ static char *center_string(centered_str, in_str) char *centered_str; char *in_str; { register int i, j; i = strlen(in_str); j = 15 - i/2; (void) sprintf (centered_str, "%*s%s%*s", j, "", in_str, 31 - i - j, ""); return centered_str; } #ifndef __TURBOC__ #if (defined(USG) || defined(atarist) || defined(HPUX)) && !defined(VMS) #if !defined(AMIGA) && !defined(MAC) && !defined(ATARIST_TC) #include #include /* The following code is provided especially for systems which -CJS- have no flock system call. It has never been tested. */ /* DEBIAN_LINUX defined because fcntlbits.h defines EX and SH the -RJW- * other way. The comment below indicates that they're not * distinguished anyways, so this should be harmless, and this does * seem to be the prevailing order (c.f. IRIX 6.5) but just in case, * they've been ifdef'ed. */ #ifdef DEBIAN_LINUX #define LOCK_SH 1 #define LOCK_EX 2 #else /* DEBIAN_LINUX */ #define LOCK_EX 1 #define LOCK_SH 2 #endif /* DEBIAN_LINUX */ #define LOCK_NB 4 #define LOCK_UN 8 /* An flock HACK. LOCK_SH and LOCK_EX are not distinguished. DO NOT release a lock which you failed to set! ALWAYS release a lock you set! */ static int flock(f, l) int f, l; { struct stat sbuf; char lockname[80]; if (fstat (f, &sbuf) < 0) return -1; #ifdef atarist (void) sprintf (lockname, (char *)prefix_file((char *)"moria.%d"), sbuf.st_ino); #else #ifdef __linux__ (void) sprintf (lockname, "/tmp/moria.%ld", sbuf.st_ino); #else (void) sprintf (lockname, "/tmp/moria.%d", sbuf.st_ino); #endif #endif if (l & LOCK_UN) return unlink(lockname); while (open (lockname, O_WRONLY|O_CREAT|O_EXCL, 0644) < 0) { if (errno != EEXIST) return -1; if (stat(lockname, &sbuf) < 0) return -1; /* Locks which last more than 10 seconds get deleted. */ if (time((long *)0) - sbuf.st_mtime > 10) { if (unlink(lockname) < 0) return -1; } else if (l & LOCK_NB) return -1; else (void) sleep(1); } return 0; } #endif #endif #endif void display_scores(show_player) int show_player; { register int i, rank; high_scores score; char input; char string[100]; int8u version_maj, version_min, patch_level; #if defined(unix) || defined(VMS) int16 player_uid; #endif #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC) || defined(APOLLO) #if defined(MAC) || defined(MSDOS) if ((highscore_fp = fopen(MORIA_TOP, "rb")) == NULL) #else if ((highscore_fp = fopen(MORIA_TOP, "r")) == NULL) #endif { (void) sprintf (string, "Error opening score file \"%s\"\n", MORIA_TOP); msg_print(string); msg_print(CNIL); return; } #endif #ifndef BSD4_3 (void) fseek(highscore_fp, (long)0, L_SET); #else (void) fseek(highscore_fp, (off_t)0, L_SET); #endif /* Read version numbers from the score file, and check for validity. */ version_maj = getc (highscore_fp); version_min = getc (highscore_fp); patch_level = getc (highscore_fp); /* Support score files from 5.2.2 to present. */ if (feof (highscore_fp)) /* An empty score file. */ ; else if ((version_maj != CUR_VERSION_MAJ) || (version_min > CUR_VERSION_MIN) || (version_min == CUR_VERSION_MIN && patch_level > PATCH_LEVEL) || (version_min == 2 && patch_level < 2) || (version_min < 2)) { msg_print("Sorry. This scorefile is from a different version of \ umoria."); msg_print (CNIL); #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC) (void) fclose (highscore_fp); #endif return; } #ifdef unix player_uid = getuid (); #else #ifdef VMS player_uid = (getgid()*1000) + getuid(); #else /* Otherwise player_uid is not used. */ #endif #endif /* set the static fileptr in save.c to the highscore file pointer */ set_fileptr(highscore_fp); rank = 1; rd_highscore(&score); while (!feof(highscore_fp)) { i = 1; clear_screen(); /* Put twenty scores on each page, on lines 2 through 21. */ while (!feof(highscore_fp) && i < 21) { /* Only show the entry if show_player false, or if the entry belongs to the current player. */ if (! show_player || #if defined(unix) || defined(VMS) score.uid == player_uid #else /* Assume microcomputers should always show every entry. */ TRUE #endif ) { (void) sprintf(string, "%-4d%8ld %-19.19s %c %-10.10s %-7.7s%3d %-22.22s", rank, score.points, score.name, score.sex, race[score.race].trace, class[score.class].title, score.lev, score.died_from); prt(string, ++i, 0); } rank++; rd_highscore(&score); } prt("Rank Points Name Sex Race Class Lvl Killed By" , 0, 0); erase_line (1, 0); prt("[Press any key to continue.]", 23, 23); input = inkey(); if (input == ESCAPE) break; } #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC) || defined(APOLLO) (void) fclose (highscore_fp); #endif } int duplicate_character () { /* Only check for duplicate characters under unix and VMS. */ #if !defined (unix) && !defined(VMS) return FALSE; #else /* ! unix && ! VMS */ high_scores score; int8u version_maj, version_min, patch_level; int16 player_uid; #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC) || defined(APOLLO) char string[80]; #endif #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC) || defined(APOLLO) #if defined(MAC) || defined(MSDOS) if ((highscore_fp = fopen(MORIA_TOP, "rb")) == NULL) #else if ((highscore_fp = fopen(MORIA_TOP, "r")) == NULL) #endif { (void) sprintf (string, "Error opening score file \"%s\"\n", MORIA_TOP); msg_print(string); msg_print(CNIL); return FALSE; } #endif #ifndef BSD4_3 (void) fseek(highscore_fp, (long)0, L_SET); #else (void) fseek(highscore_fp, (off_t)0, L_SET); #endif /* Read version numbers from the score file, and check for validity. */ version_maj = getc (highscore_fp); version_min = getc (highscore_fp); patch_level = getc (highscore_fp); /* Support score files from 5.2.2 to present. */ if (feof (highscore_fp)) /* An empty score file. */ return FALSE; if ((version_maj != CUR_VERSION_MAJ) || (version_min > CUR_VERSION_MIN) || (version_min == CUR_VERSION_MIN && patch_level > PATCH_LEVEL) || (version_min == 2 && patch_level < 2) || (version_min < 2)) { msg_print("Sorry. This scorefile is from a different version of \ umoria."); msg_print (CNIL); #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC) || defined(APOLLO) (void) fclose (highscore_fp); #endif return FALSE; } /* set the static fileptr in save.c to the highscore file pointer */ set_fileptr(highscore_fp); #ifdef unix player_uid = getuid (); #else #ifdef VMS player_uid = (getgid()*1000) + getuid(); #else player_uid = 0; #endif #endif rd_highscore(&score); while (!feof(highscore_fp)) { if (score.uid == player_uid && score.birth_date == birth_date && score.class == py.misc.pclass && score.race == py.misc.prace && score.sex == (py.misc.male ? 'M' : 'F') && strcmp (score.died_from, "(saved)")) return TRUE; rd_highscore(&score); } #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC) (void) fclose (highscore_fp); #endif return FALSE; #endif /* ! unix && ! VMS */ } /* Prints the gravestone of the character -RAK- */ static void print_tomb() { vtype str, tmp_str; register int i; char day[11]; register char *p; #ifdef MAC char func; int ok; #endif clear_screen(); put_buffer ("_______________________", 1, 15); put_buffer ("/", 2, 14); put_buffer ("\\ ___", 2, 38); put_buffer ("/", 3, 13); put_buffer ("\\ ___ / \\ ___", 3, 39); put_buffer ("/ RIP \\ \\ : : / \\", 4, 12); put_buffer ("/", 5, 11); put_buffer ("\\ : _;,,,;_ : :", 5, 41); (void) sprintf (str, "/%s\\,;_ _;,,,;_", center_string (tmp_str, py.misc.name)); put_buffer (str, 6, 10); put_buffer ("| the | ___", 7, 9); if (!total_winner) p = title_string (); else p = "Magnificent"; (void) sprintf (str, "| %s | / \\", center_string (tmp_str, p)); put_buffer (str, 8, 9); put_buffer ("|", 9, 9); put_buffer ("| : :", 9, 43); if (!total_winner) p = class[py.misc.pclass].title; else if (py.misc.male) p = "*King*"; else p = "*Queen*"; (void) sprintf(str,"| %s | _;,,,;_ ____", center_string (tmp_str, p)); put_buffer (str, 10, 9); (void) sprintf (str, "Level : %d", (int) py.misc.lev); (void) sprintf (str,"| %s | / \\", center_string (tmp_str, str)); put_buffer (str, 11, 9); (void) sprintf(str, "%ld Exp", py.misc.exp); (void) sprintf(str,"| %s | : :", center_string (tmp_str, str)); put_buffer (str, 12, 9); (void) sprintf(str, "%ld Au", py.misc.au); (void) sprintf(str,"| %s | : :", center_string (tmp_str, str)); put_buffer (str, 13, 9); (void) sprintf(str, "Died on Level : %d", dun_level); (void) sprintf(str,"| %s | _;,,,,;_", center_string (tmp_str, str)); put_buffer (str, 14, 9); put_buffer ("| killed by |", 15, 9); p = died_from; i = strlen (p); p[i] = '.'; /* add a trailing period */ p[i+1] = '\0'; (void) sprintf(str, "| %s |", center_string (tmp_str, p)); put_buffer (str, 16, 9); p[i] = '\0'; /* strip off the period */ date(day); (void) sprintf(str, "| %s |", center_string (tmp_str, day)); put_buffer (str, 17, 9); put_buffer ("*| * * * * * * | *", 18, 8); put_buffer ("________)/\\\\_)_/___(\\/___(//_\\)/_\\//__\\\\(/_|_)_______", 19, 0); retry: flush(); #ifdef MAC /* On Mac, file_character() gets file name via std file dialog */ /* So, the prompt for character record cannot be made to do double duty */ put_buffer ("('F' - Save record in file / 'Y' - Display record on screen \ / 'N' - Abort)", 23, 0); put_buffer ("Character record [F/Y/N]?", 22, 0); do { func = inkey(); switch (func) { case 'f': case 'F': func = 'F'; ok = TRUE; break; case 'y': case 'Y': func = 'Y'; ok = TRUE; break; case 'n': case 'N': func = 'N'; ok = TRUE; break; default: bell(); ok = FALSE; break; } } while (!ok); if (func != 'N') #else put_buffer ("(ESC to abort, return to print on screen, or file name)", 23, 0); put_buffer ("Character record?", 22, 0); if (get_string (str, 22, 18, 60)) #endif { for (i = 0; i < INVEN_ARRAY_SIZE; i++) { known1(&inventory[i]); known2(&inventory[i]); } calc_bonuses (); #ifdef MAC if (func == 'F') { if (!file_character()) goto retry; } #else if (str[0]) { if (!file_character (str)) goto retry; } #endif else { clear_screen (); display_char (); put_buffer ("Type ESC to skip the inventory:", 23, 0); if (inkey() != ESCAPE) { clear_screen (); msg_print ("You are using:"); (void) show_equip (TRUE, 0); msg_print (CNIL); msg_print ("You are carrying:"); clear_from (1); (void) show_inven (0, inven_ctr-1, TRUE, 0, CNIL); msg_print (CNIL); } } } } /* Calculates the total number of points earned -JWT- */ int32 total_points() { int32 total; int i; total = py.misc.max_exp + (100 * py.misc.max_dlv); total += py.misc.au / 100; for (i = 0; i < INVEN_ARRAY_SIZE; i++) total += item_value(&inventory[i]); total += dun_level*50; /* Don't ever let the score decrease from one save to the next. */ if (max_score > total) return max_score; return total; } /* Enters a players name on the top twenty list -JWT- */ static void highscores() { high_scores old_entry, new_entry, entry; int i; char *tmp; int8u version_maj, version_min, patch_level; long curpos; #if defined(VMS) || defined(MSDOS) || defined(AMIGA) || defined(MAC) || defined(APOLLO) char string[100]; #endif clear_screen(); if (noscore) return; if (panic_save == 1) { msg_print("Sorry, scores for games restored from panic save files \ are not saved."); return; } new_entry.points = total_points(); new_entry.birth_date = birth_date; #ifdef unix new_entry.uid = getuid(); #else #ifdef VMS new_entry.uid = (getgid()*1000) + getuid(); #else new_entry.uid = 0; #endif #endif new_entry.mhp = py.misc.mhp; new_entry.chp = py.misc.chp; new_entry.dun_level = dun_level; new_entry.lev = py.misc.lev; new_entry.max_dlv = py.misc.max_dlv; new_entry.sex = (py.misc.male ? 'M' : 'F'); new_entry.race = py.misc.prace; new_entry.class = py.misc.pclass; (void) strcpy(new_entry.name, py.misc.name); tmp = died_from; if ('a' == *tmp) { if ('n' == *(++tmp)) { tmp++; } while (isspace(*tmp)) { tmp++; } } (void) strcpy(new_entry.died_from, tmp); /* First, get a lock on the high score file so no-one else tries */ /* to write to it while we are using it, on VMS and IBMPCs only one process can have the file open at a time, so we just open it here */ #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC) #if defined(MAC) || defined(MSDOS) if ((highscore_fp = fopen(MORIA_TOP, "rb+")) == NULL) #else if ((highscore_fp = fopen(MORIA_TOP, "r+")) == NULL) #endif { (void) sprintf (string, "Error opening score file \"%s\"\n", MORIA_TOP); msg_print(string); msg_print(CNIL); return; } #else #ifdef ATARIST_TC /* 'lock' always succeeds on the Atari ST */ #else if (0 != flock((int)fileno(highscore_fp), LOCK_EX)) { msg_print("Error gaining lock for score file"); msg_print(CNIL); return; } #endif #endif /* Search file to find where to insert this character, if uid != 0 and find same uid/sex/race/class combo then exit without saving this score */ /* Seek to the beginning of the file just to be safe. */ #ifndef BSD4_3 (void) fseek(highscore_fp, (long)0, L_SET); #else (void) fseek(highscore_fp, (off_t)0, L_SET); #endif /* Read version numbers from the score file, and check for validity. */ version_maj = getc (highscore_fp); version_min = getc (highscore_fp); patch_level = getc (highscore_fp); /* If this is a new scorefile, it should be empty. Write the current version numbers to the score file. */ if (feof (highscore_fp)) { /* Seek to the beginning of the file just to be safe. */ #ifndef BSD4_3 (void) fseek(highscore_fp, (long)0, L_SET); #else (void) fseek(highscore_fp, (off_t)0, L_SET); #endif (void) putc (CUR_VERSION_MAJ, highscore_fp); (void) putc (CUR_VERSION_MIN, highscore_fp); (void) putc (PATCH_LEVEL, highscore_fp); /* must fseek() before can change read/write mode */ #ifndef BSD4_3 #ifdef ATARIST_TC /* no fseek relative to current position allowed */ (void) fseek (highscore_fp, (long)ftell (highscore_fp), L_SET); #else (void) fseek(highscore_fp, (long)0, L_INCR); #endif #else (void) fseek(highscore_fp, (off_t)0, L_INCR); #endif } /* Support score files from 5.2.2 to present. */ else if ((version_maj != CUR_VERSION_MAJ) || (version_min > CUR_VERSION_MIN) || (version_min == CUR_VERSION_MIN && patch_level > PATCH_LEVEL) || (version_min == 2 && patch_level < 2) || (version_min < 2)) { /* No need to print a message, a subsequent call to display_scores() will print a message. */ #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC) (void) fclose (highscore_fp); #endif return; } /* set the static fileptr in save.c to the highscore file pointer */ set_fileptr(highscore_fp); i = 0; curpos = ftell (highscore_fp); rd_highscore(&old_entry); while (!feof(highscore_fp)) { if (new_entry.points >= old_entry.points) break; /* under unix and VMS, only allow one sex/race/class combo per person, on single user system, allow any number of entries, but try to prevent multiple entries per character by checking for case when birthdate/sex/race/class are the same, and died_from of scorefile entry is "(saved)" */ else if (((new_entry.uid != 0 && new_entry.uid == old_entry.uid) || (new_entry.uid == 0 &&!strcmp(old_entry.died_from,"(saved)") && new_entry.birth_date == old_entry.birth_date)) && new_entry.sex == old_entry.sex && new_entry.race == old_entry.race && new_entry.class == old_entry.class) { #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC) || defined(APOLLO) (void) fclose (highscore_fp); #endif return; } else if (++i >= SCOREFILE_SIZE) { /* only allow one thousand scores in the score file */ #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC) (void) fclose (highscore_fp); #endif return; } curpos = ftell (highscore_fp); rd_highscore(&old_entry); } if (feof(highscore_fp)) { /* write out new_entry at end of file */ #ifndef BSD4_3 (void) fseek (highscore_fp, curpos, L_SET); #else (void) fseek (highscore_fp, (off_t)curpos, L_SET); #endif wr_highscore(&new_entry); } else { entry = new_entry; while (!feof(highscore_fp)) { #ifndef BSD4_3 #if defined(ATARIST_TC) || defined(__TURBOC__) /* No fseek with negative offset allowed. */ (void) fseek(highscore_fp, (long)ftell(highscore_fp) - sizeof(high_scores) - sizeof (char), L_SET); #else (void) fseek(highscore_fp, -(long)sizeof(high_scores)-(long)sizeof(char), L_INCR); #endif #else (void) fseek(highscore_fp, -(off_t)sizeof(high_scores)-(off_t)sizeof(char), L_INCR); #endif wr_highscore(&entry); /* under unix and VMS, only allow one sex/race/class combo per person, on single user system, allow any number of entries, but try to prevent multiple entries per character by checking for case when birthdate/sex/race/class are the same, and died_from of scorefile entry is "(saved)" */ if (((new_entry.uid != 0 && new_entry.uid == old_entry.uid) || (new_entry.uid == 0 &&!strcmp(old_entry.died_from,"(saved)") && new_entry.birth_date == old_entry.birth_date)) && new_entry.sex == old_entry.sex && new_entry.race == old_entry.race && new_entry.class == old_entry.class) break; entry = old_entry; /* must fseek() before can change read/write mode */ #ifndef BSD4_3 #ifdef ATARIST_TC /* No fseek relative to current position allowed. */ (void) fseek(highscore_fp, (long)ftell(highscore_fp), L_SET); #else (void) fseek(highscore_fp, (long)0, L_INCR); #endif #else (void) fseek(highscore_fp, (off_t)0, L_INCR); #endif curpos = ftell (highscore_fp); rd_highscore(&old_entry); } if (feof(highscore_fp)) { #ifndef BSD4_3 (void) fseek (highscore_fp, curpos, L_SET); #else (void) fseek (highscore_fp, (off_t)curpos, L_SET); #endif wr_highscore(&entry); } } #if !defined(VMS) && !defined(MSDOS) && !defined(AMIGA) && !defined(MAC) && !defined(APOLLO) #ifdef ATARIST_TC /* Flock never called for Atari ST with TC. */ #else (void) flock((int)fileno(highscore_fp), LOCK_UN); #endif #else (void) fclose (highscore_fp); #endif } /* Change the player into a King! -RAK- */ static void kingly() { register struct misc *p_ptr; register char *p; /* Change the character attributes. */ dun_level = 0; (void) strcpy(died_from, "Ripe Old Age"); p_ptr = &py.misc; (void) restore_level (); p_ptr->lev += MAX_PLAYER_LEVEL; p_ptr->au += 250000L; p_ptr->max_exp += 5000000L; p_ptr->exp = p_ptr->max_exp; /* Let the player know that he did good. */ clear_screen(); put_buffer("#", 1, 34); put_buffer("#####", 2, 32); put_buffer("#", 3, 34); put_buffer(",,, $$$ ,,,", 4, 28); put_buffer(",,=$ \"$$$$$\" $=,,", 5, 24); put_buffer(",$$ $$$ $$,", 6, 22); put_buffer("*> <*> <*", 7, 22); put_buffer("$$ $$$ $$", 8, 22); put_buffer("\"$$ $$$ $$\"", 9, 22); put_buffer("\"$$ $$$ $$\"", 10, 23); p = "*#########*#########*"; put_buffer(p, 11, 24); put_buffer(p, 12, 24); put_buffer("Veni, Vidi, Vici!", 15, 26); put_buffer("I came, I saw, I conquered!", 16, 21); if (p_ptr->male) put_buffer("All Hail the Mighty King!", 17, 22); else put_buffer("All Hail the Mighty Queen!", 17, 22); flush(); pause_line(23); } /* Handles the gravestone end top-twenty routines -RAK- */ void exit_game () { #ifdef MAC /* Prevent strange things from happening */ enablefilemenu(FALSE); #endif /* What happens upon dying. -RAK- */ msg_print(CNIL); flush (); /* flush all input */ nosignals (); /* Can't interrupt or suspend. */ /* If the game has been saved, then save sets turn back to -1, which inhibits the printing of the tomb. */ if (turn >= 0) { if (total_winner) kingly(); print_tomb(); } if (character_generated && !character_saved) #ifdef MAC (void) save_char (TRUE); /* Save the memory at least. */ #else (void) save_char (); /* Save the memory at least. */ #endif /* add score to scorefile if applicable */ if (character_generated) { /* Clear character_saved, strange thing to do, but it prevents inkey() from recursively calling exit_game() when there has been an eof on stdin detected. */ character_saved = FALSE; highscores(); display_scores (TRUE); } erase_line (23, 0); restore_term (); #ifdef MAC /* Undo what has been done */ enablefilemenu(TRUE); /* Long jump back into the Mac wrapper, in lieu of exit () */ goback(); #else exit (0); #endif } moria-5.6.debian.1/source/types.h0000644000175000017500000003411711074756544015023 0ustar pjbpjb/* source/types.h: global type declarations Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ /* Use ISO C99 standard declarations to get correct lengths; if you have an old compiler; #define NO_STDINT. */ #if defined(NO_STDINT) #include typedef unsigned char int8u; typedef short int16; typedef unsigned short int16u; #if (UINT_MAX>0xFFFF) typedef int int32; typedef unsigned int int32u; #else typedef long int32; typedef unsigned long int32u; #endif #else #include typedef uint_least8_t int8u; typedef int_least16_t int16; typedef uint_least16_t int16u; typedef int_least32_t int32; typedef uint_least32_t int32u; #endif /* some machines will not accept 'signed char' as a type, and some accept it but still treat it like an unsigned character, let's just avoid it, any variable which can ever hold a negative value must be 16 or 32 bits */ #define VTYPESIZ 80 #define BIGVTYPESIZ 160 typedef char vtype[VTYPESIZ]; /* note that since its output can easily exceed 80 characters, objdes must always be called with a bigvtype as the first paramter */ typedef char bigvtype[BIGVTYPESIZ]; typedef char stat_type[7]; /* Many of the character fields used to be fixed length, which greatly increased the size of the executable. I have replaced many fixed length fields with variable length ones. */ /* all fields are given the smallest possbile type, and all fields are aligned within the structure to their natural size boundary, so that the structures contain no padding and are minimum size */ /* bit fields are only used where they would cause a large reduction in data size, they should not be used otherwise because their use results in larger and slower code */ typedef struct creature_type { char *name; /* Descrip of creature */ int32u cmove; /* Bit field */ int32u spells; /* Creature spells */ int16u cdefense; /* Bit field */ int16u mexp; /* Exp value for kill */ int8u sleep; /* Inactive counter/10 */ int8u aaf; /* Area affect radius */ int8u ac; /* AC */ int8u speed; /* Movement speed+10 */ int8u cchar; /* Character rep. */ int8u hd[2]; /* Creatures hit die */ int8u damage[4]; /* Type attack and damage*/ int8u level; /* Level of creature */ } creature_type; typedef struct m_attack_type /* Monster attack and damage types */ { int8u attack_type; int8u attack_desc; int8u attack_dice; int8u attack_sides; } m_attack_type; typedef struct recall_type /* Monster memories. -CJS- */ { int32u r_cmove; int32u r_spells; int16u r_kills, r_deaths; int16u r_cdefense; int8u r_wake, r_ignore; int8u r_attacks[MAX_MON_NATTACK]; } recall_type; typedef struct monster_type { int16 hp; /* Hit points */ int16 csleep; /* Inactive counter */ int16 cspeed; /* Movement speed */ int16u mptr; /* Pointer into creature*/ /* Note: fy, fx, and cdis constrain dungeon size to less than 256 by 256 */ int8u fy; /* Y Pointer into map */ int8u fx; /* X Pointer into map */ int8u cdis; /* Cur dis from player */ int8u ml; int8u stunned; int8u confused; } monster_type; typedef struct treasure_type { char *name; /* Object name */ int32u flags; /* Special flags */ int8u tval; /* Category number */ int8u tchar; /* Character representation*/ int16 p1; /* Misc. use variable */ int32 cost; /* Cost of item */ int8u subval; /* Sub-category number */ int8u number; /* Number of items */ int16u weight; /* Weight */ int16 tohit; /* Plusses to hit */ int16 todam; /* Plusses to damage */ int16 ac; /* Normal AC */ int16 toac; /* Plusses to AC */ int8u damage[2]; /* Damage when hits */ int8u level; /* Level item first found */ } treasure_type; /* only damage, ac, and tchar are constant; level could possibly be made constant by changing index instead; all are used rarely */ /* extra fields x and y for location in dungeon would simplify pusht() */ /* making inscrip a pointer and mallocing space does not work, there are two many places where inven_types are copied, which results in dangling pointers, so we use a char array for them instead */ #define INSCRIP_SIZE 13 /* notice alignment, must be 4*x + 1 */ typedef struct inven_type { int16u index; /* Index to object_list */ int8u name2; /* Object special name */ char inscrip[INSCRIP_SIZE]; /* Object inscription */ int32u flags; /* Special flags */ int8u tval; /* Category number */ int8u tchar; /* Character representation*/ int16 p1; /* Misc. use variable */ int32 cost; /* Cost of item */ int8u subval; /* Sub-category number */ int8u number; /* Number of items */ int16u weight; /* Weight */ int16 tohit; /* Plusses to hit */ int16 todam; /* Plusses to damage */ int16 ac; /* Normal AC */ int16 toac; /* Plusses to AC */ int8u damage[2]; /* Damage when hits */ int8u level; /* Level item first found */ int8u ident; /* Identify information */ } inven_type; #define PLAYER_NAME_SIZE 27 typedef struct player_type { struct misc { char name[PLAYER_NAME_SIZE]; /* Name of character */ int8u male; /* Sex of character */ int32 au; /* Gold */ int32 max_exp; /* Max experience */ int32 exp; /* Cur experience */ int16u exp_frac; /* Cur exp fraction * 2^16 */ int16u age; /* Characters age */ int16u ht; /* Height */ int16u wt; /* Weight */ int16u lev; /* Level */ int16u max_dlv; /* Max level explored */ int16 srh; /* Chance in search */ int16 fos; /* Frenq of search */ int16 bth; /* Base to hit */ int16 bthb; /* BTH with bows */ int16 mana; /* Mana points */ int16 mhp; /* Max hit pts */ int16 ptohit; /* Plusses to hit */ int16 ptodam; /* Plusses to dam */ int16 pac; /* Total AC */ int16 ptoac; /* Magical AC */ int16 dis_th; /* Display +ToHit */ int16 dis_td; /* Display +ToDam */ int16 dis_ac; /* Display +ToAC */ int16 dis_tac; /* Display +ToTAC */ int16 disarm; /* % to Disarm */ int16 save; /* Saving throw */ int16 sc; /* Social Class */ int16 stl; /* Stealth factor */ int8u pclass; /* # of class */ int8u prace; /* # of race */ int8u hitdie; /* Char hit die */ int8u expfact; /* Experience factor */ int16 cmana; /* Cur mana pts */ int16u cmana_frac; /* Cur mana fraction * 2^16 */ int16 chp; /* Cur hit pts */ int16u chp_frac; /* Cur hit fraction * 2^16 */ char history[4][60]; /* History record */ } misc; /* Stats now kept in arrays, for more efficient access. -CJS- */ struct stats { int8u max_stat[6]; /* What is restored */ int8u cur_stat[6]; /* What is natural */ int16 mod_stat[6]; /* What is modified, may be +/- */ int8u use_stat[6]; /* What is used */ } stats; struct flags { int32u status; /* Status of player */ int16 rest; /* Rest counter */ int16 blind; /* Blindness counter */ int16 paralysis; /* Paralysis counter */ int16 confused; /* Confusion counter */ int16 food; /* Food counter */ int16 food_digested; /* Food per round */ int16 protection; /* Protection fr. evil */ int16 speed; /* Cur speed adjust */ int16 fast; /* Temp speed change */ int16 slow; /* Temp speed change */ int16 afraid; /* Fear */ int16 poisoned; /* Poisoned */ int16 image; /* Hallucinate */ int16 protevil; /* Protect VS evil */ int16 invuln; /* Increases AC */ int16 hero; /* Heroism */ int16 shero; /* Super Heroism */ int16 blessed; /* Blessed */ int16 resist_heat; /* Timed heat resist */ int16 resist_cold; /* Timed cold resist */ int16 detect_inv; /* Timed see invisible */ int16 word_recall; /* Timed teleport level*/ int16 see_infra; /* See warm creatures */ int16 tim_infra; /* Timed infra vision */ int8u see_inv; /* Can see invisible */ int8u teleport; /* Random teleportation*/ int8u free_act; /* Never paralyzed */ int8u slow_digest; /* Lower food needs */ int8u aggravate; /* Aggravate monsters */ int8u fire_resist; /* Resistance to fire */ int8u cold_resist; /* Resistance to cold */ int8u acid_resist; /* Resistance to acid */ int8u regenerate; /* Regenerate hit pts */ int8u lght_resist; /* Resistance to light */ int8u ffall; /* No damage falling */ int8u sustain_str; /* Keep strength */ int8u sustain_int; /* Keep intelligence */ int8u sustain_wis; /* Keep wisdom */ int8u sustain_con; /* Keep constitution */ int8u sustain_dex; /* Keep dexterity */ int8u sustain_chr; /* Keep charisma */ int8u confuse_monster; /* Glowing hands. */ int8u new_spells; /* Number of spells can learn. */ } flags; } player_type; typedef struct spell_type { /* spell name is stored in spell_names[] array at index i, +31 if priest */ int8u slevel; int8u smana; int8u sfail; int8u sexp; /* 1/4 of exp gained for learning spell */ } spell_type; typedef struct race_type { char *trace; /* Type of race */ int16 str_adj; /* adjustments */ int16 int_adj; int16 wis_adj; int16 dex_adj; int16 con_adj; int16 chr_adj; int8u b_age; /* Base age of character */ int8u m_age; /* Maximum age of character */ int8u m_b_ht; /* base height for males */ int8u m_m_ht; /* mod height for males */ int8u m_b_wt; /* base weight for males */ int8u m_m_wt; /* mod weight for males */ int8u f_b_ht; /* base height females */ int8u f_m_ht; /* mod height for females */ int8u f_b_wt; /* base weight for female */ int8u f_m_wt; /* mod weight for females */ int16 b_dis; /* base chance to disarm */ int16 srh; /* base chance for search */ int16 stl; /* Stealth of character */ int16 fos; /* frequency of auto search */ int16 bth; /* adj base chance to hit */ int16 bthb; /* adj base to hit with bows */ int16 bsav; /* Race base for saving throw */ int8u bhitdie; /* Base hit points for race */ int8u infra; /* See infra-red */ int8u b_exp; /* Base experience factor */ int8u rtclass; /* Bit field for class types */ } race_type; typedef struct class_type { char *title; /* type of class */ int8u adj_hd; /* Adjust hit points */ int8u mdis; /* mod disarming traps */ int8u msrh; /* modifier to searching */ int8u mstl; /* modifier to stealth */ int8u mfos; /* modifier to freq-of-search */ int8u mbth; /* modifier to base to hit */ int8u mbthb; /* modifier to base to hit - bows*/ int8u msav; /* Class modifier to save */ int16 madj_str; /* Class modifier for strength */ int16 madj_int; /* Class modifier for intelligence*/ int16 madj_wis; /* Class modifier for wisdom */ int16 madj_dex; /* Class modifier for dexterity */ int16 madj_con; /* Class modifier for constitution*/ int16 madj_chr; /* Class modifier for charisma */ int8u spell; /* class use mage spells */ int8u m_exp; /* Class experience factor */ int8u first_spell_lev;/* First level where class can use spells. */ } class_type; typedef struct background_type { char *info; /* History information */ int8u roll; /* Die roll needed for history */ int8u chart; /* Table number */ int8u next; /* Pointer to next table */ int8u bonus; /* Bonus to the Social Class+50 */ } background_type; typedef struct cave_type { #ifdef AMIGA /* This reduces the size from 64 bits to 32 bits. */ unsigned int cptr : 8; unsigned int tptr : 8; unsigned int fval : 8; #else int8u cptr; int8u tptr; int8u fval; #endif #if !defined(MSDOS) && !defined(ATARIST_MWC) unsigned int lr : 1; /* room should be lit with perm light, walls with this set should be perm lit after tunneled out */ unsigned int fm : 1; /* field mark, used for traps/doors/stairs, object is hidden if fm is FALSE */ unsigned int pl : 1; /* permanent light, used for walls and lighted rooms */ unsigned int tl : 1; /* temporary light, used for player's lamp light,etc.*/ #else #ifndef __TURBOC__ /* this is not legal ANSI C, this is a MSC extension, which will use 1 byte for the bitfields whereas MSC uses 2 bytes for the bitfields above */ /* this is also a MWC extension on the Atari ST */ unsigned char lr : 1; unsigned char fm : 1; unsigned char pl : 1; unsigned char tl : 1; #else unsigned lr : 1; unsigned fm : 1; unsigned pl : 1; unsigned tl : 1; #endif #endif } cave_type; typedef struct owner_type { char *owner_name; int16 max_cost; int8u max_inflate; int8u min_inflate; int8u haggle_per; int8u owner_race; int8u insult_max; } owner_type; typedef struct inven_record { int32 scost; inven_type sitem; } inven_record; typedef struct store_type { int32 store_open; int16 insult_cur; int8u owner; int8u store_ctr; int16u good_buy; int16u bad_buy; inven_record store_inven[STORE_INVEN_MAX]; } store_type; /* 64 bytes for this structure */ typedef struct high_scores { int32 points; int32 birth_date; int16 uid; int16 mhp; int16 chp; int8u dun_level; int8u lev; int8u max_dlv; int8u sex; int8u race; int8u class; char name[PLAYER_NAME_SIZE]; char died_from[25]; } high_scores; moria-5.6.debian.1/source/signals.c0000644000175000017500000002124111074756544015304 0ustar pjbpjb/* source/signals.c: signal handlers Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ /* This signal package was brought to you by -JEW- */ /* Completely rewritten by -CJS- */ /* To find out what system we're on. */ #include #include "config.h" #include "constant.h" /* Signals have no significance on the Mac */ #ifdef MAC void nosignals() { } void signals() { } void init_signals() { } #else /* a non-Mac system */ /* Since libc6, linux (Debian, at least) defaults to BSD signal(). This */ /* expects SYSV. Thus, DEBIAN_LINUX uses the sysv_signal call, everyone */ /* else uses just signal. RJW 00_0528 */ #ifdef DEBIAN_LINUX #define MSIGNAL sysv_signal #else #define MSIGNAL signal #endif #ifdef ATARIST_MWC /* need these for atari st, but for unix, must include signals.h first, or else suspend won't be properly declared */ #include "types.h" #include "externs.h" #endif /* skip most of the file on an ATARI ST */ /* commented away most single handling for Atari ST TC too, as this doesn't work as it should. */ #if !defined(ATARIST_MWC) && !defined(ATARIST_TC) #if defined(SYS_V) && defined(lint) /* for AIX, prevent hundreds of unnecessary lint errors, define before signal.h is included */ #define _h_IEEETRAP typedef struct { int stuff; } fpvmach; #endif /* must include before externs.h, because that uses SIGTSTP */ #include #include "types.h" #include "externs.h" #ifndef USG /* only needed for Berkeley UNIX */ #include #include #endif #ifdef USG #ifndef ATARIST_MWC #include #endif #else #include #endif #ifndef VMS #ifdef USG void exit(); #ifdef __TURBOC__ void sleep(); #else unsigned sleep(); #endif #endif #endif static int error_sig = -1; static int signal_count = 0; /*ARGSUSED*/ #ifndef USG #ifdef __386BSD__ static void signal_handler(sig, code, scp) #else static int signal_handler(sig, code, scp) #endif int sig, code; struct sigcontext *scp; { int smask; smask = sigsetmask(0) | (1 << sig); #else #if defined(__TURBOC__) || defined(AMIGA) static void signal_handler(sig) #else static int signal_handler(sig) #endif int sig; { #endif if(error_sig >= 0) /* Ignore all second signals. */ { if(++signal_count > 10) /* Be safe. We will die if persistent enough. */ (void) MSIGNAL(sig, SIG_DFL); return; } error_sig = sig; /* Allow player to think twice. Wizard may force a core dump. */ if (sig == SIGINT #if !defined(MSDOS) && !defined(AMIGA) && !defined(ATARIST_TC) || sig == SIGQUIT #endif ) { if (death) (void) MSIGNAL(sig, SIG_IGN); /* Can't quit after death. */ else if (!character_saved && character_generated) { if (!get_check("Really commit *Suicide*?")) { if (turn > 0) disturb(1, 0); erase_line(0, 0); put_qio(); error_sig = -1; #ifdef USG (void) MSIGNAL(sig, signal_handler);/* Have to restore handler. */ #else (void) sigsetmask(smask); #endif /* in case control-c typed during msg_print */ if (wait_for_more) put_buffer(" -more-", MSG_LINE, 0); put_qio(); return; /* OK. We don't quit. */ } (void) strcpy(died_from, "Interrupting"); } else (void) strcpy(died_from, "Abortion"); prt("Interrupt!", 0, 0); death = TRUE; exit_game(); } /* Die. */ prt( "OH NO!!!!!! A gruesome software bug LEAPS out at you. There is NO defense!", 23, 0); if (!death && !character_saved && character_generated) { panic_save = 1; prt("Your guardian angel is trying to save you.", 0, 0); (void) sprintf(died_from,"(panic save %d)",sig); if (!save_char()) { (void) strcpy(died_from, "software bug"); death = TRUE; turn = -1; } } else { death = TRUE; (void) _save_char(savefile); /* Quietly save the memory anyway. */ } restore_term(); #if !defined(MSDOS) && !defined(AMIGA) && !defined(ATARIST_TC) /* always generate a core dump */ (void) MSIGNAL(sig, SIG_DFL); (void) kill(getpid(), sig); (void) sleep(5); #endif exit(1); } #endif /* ATARIST_MWC, ATARIST_TC */ #ifndef USG static int mask; #endif void nosignals() { #if !defined(ATARIST_MWC) && !defined(ATARIST_TC) #ifdef SIGTSTP #if defined(atarist) && defined(__GNUC__) (void) MSIGNAL(SIGTSTP, (__Sigfunc)SIG_IGN); #else (void) MSIGNAL(SIGTSTP, SIG_IGN); #endif #ifndef USG mask = sigsetmask(0); #endif #endif if (error_sig < 0) error_sig = 0; #endif } void signals() { #if !defined(ATARIST_MWC) && !defined(ATARIST_TC) #ifdef SIGTSTP #if defined(atarist) && defined(__GNUC__) (void) MSIGNAL(SIGTSTP, (__Sigfunc)suspend); #else #ifdef __386BSD__ (void) MSIGNAL(SIGTSTP, (sig_t)suspend); #else (void) MSIGNAL(SIGTSTP, suspend); #endif #endif #ifndef USG (void) sigsetmask(mask); #endif #endif if (error_sig == 0) error_sig = -1; #endif } void init_signals() { #if !defined(ATARIST_MWC) && !defined(ATARIST_TC) /* No signals for Atari ST compiled with MWC or TC. */ (void) MSIGNAL(SIGINT, signal_handler); #if defined(atarist) && defined(__GNUC__) /* Atari ST compiled with GNUC has most signals, but we need a cast in every call to signal. */ (void) MSIGNAL(SIGINT, (__Sigfunc)signal_handler); (void) MSIGNAL(SIGQUIT, (__Sigfunc)signal_handler); (void) MSIGNAL(SIGTSTP,(__Sigfunc)SIG_IGN); (void) MSIGNAL(SIGILL, (__Sigfunc)signal_handler); (void) MSIGNAL(SIGHUP, (__Sigfunc)SIG_IGN); (void) MSIGNAL(SIGTRAP,(__Sigfunc)signal_handler); (void) MSIGNAL(SIGIOT, (__Sigfunc)signal_handler); (void) MSIGNAL(SIGEMT, (__Sigfunc)signal_handler); (void) MSIGNAL(SIGKILL, (__Sigfunc)signal_handler); (void) MSIGNAL(SIGBUS, (__Sigfunc)signal_handler); (void) MSIGNAL(SIGSEGV, (__Sigfunc)signal_handler); (void) MSIGNAL(SIGSYS, (__Sigfunc)signal_handler); (void) MSIGNAL(SIGTERM,(__Sigfunc)signal_handler); (void) MSIGNAL(SIGPIPE, (__Sigfunc)signal_handler); #else /* Everybody except the atari st. */ (void) MSIGNAL(SIGINT, signal_handler); (void) MSIGNAL(SIGFPE, signal_handler); #if defined(MSDOS) /* many fewer signals under MSDOS */ #else #ifdef AMIGA /* (void) MSIGNAL(SIGINT, signal_handler); */ (void) MSIGNAL(SIGTERM, signal_handler); (void) MSIGNAL(SIGABRT, signal_handler); /* (void) MSIGNAL(SIGFPE, signal_handler); */ (void) MSIGNAL(SIGILL, signal_handler); (void) MSIGNAL(SIGSEGV, signal_handler); #else /* Everybody except Atari, MSDOS, and Amiga. */ /* Ignore HANGUP, and let the EOF code take care of this case. */ (void) MSIGNAL(SIGHUP, SIG_IGN); (void) MSIGNAL(SIGQUIT, signal_handler); (void) MSIGNAL(SIGILL, signal_handler); (void) MSIGNAL(SIGTRAP, signal_handler); (void) MSIGNAL(SIGIOT, signal_handler); #ifdef SIGEMT /* in BSD systems */ (void) MSIGNAL(SIGEMT, signal_handler); #endif #ifdef SIGDANGER /* in SYSV systems */ (void) MSIGNAL(SIGDANGER, signal_handler); #endif (void) MSIGNAL(SIGKILL, signal_handler); (void) MSIGNAL(SIGBUS, signal_handler); (void) MSIGNAL(SIGSEGV, signal_handler); #ifdef SIGSYS (void) MSIGNAL(SIGSYS, signal_handler); #endif (void) MSIGNAL(SIGTERM, signal_handler); (void) MSIGNAL(SIGPIPE, signal_handler); #ifdef SIGXCPU /* BSD */ (void) MSIGNAL(SIGXCPU, signal_handler); #endif #ifdef SIGPWR /* SYSV */ (void) MSIGNAL(SIGPWR, signal_handler); #endif #endif #endif #endif #endif } void ignore_signals() { #if !defined(ATARIST_MWC) (void) MSIGNAL(SIGINT, SIG_IGN); #ifdef SIGQUIT (void) MSIGNAL(SIGQUIT, SIG_IGN); #endif #endif } void default_signals() { #if !defined(ATARIST_MWC) (void) MSIGNAL(SIGINT, SIG_DFL); #ifdef SIGQUIT (void) MSIGNAL(SIGQUIT, SIG_DFL); #endif #endif } void restore_signals() { #if !defined(ATARIST_MWC) #if defined(atarist) && defined(__GNUC__) (void) MSIGNAL(SIGINT, (__Sigfunc)signal_handler); #else (void) MSIGNAL(SIGINT, signal_handler); #endif #ifdef SIGQUIT #if defined(atarist) && defined(__GNUC__) (void) MSIGNAL(SIGQUIT, (__Sigfunc)signal_handler); #else (void) MSIGNAL(SIGQUIT, signal_handler); #endif #endif #endif } #endif /* big Mac conditional */ moria-5.6.debian.1/source/moria2.c0000644000175000017500000004617511074756544015052 0ustar pjbpjb/* source/moria2.c: misc code, mainly handles player movement, inventory, etc Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #if defined(LINT_ARGS) static int see_wall(int, int, int); static int see_nothing(int, int, int); #else static int see_wall(); #endif /* Change a trap from invisible to visible -RAK- */ /* Note: Secret doors are handled here */ void change_trap(y, x) register int y, x; { register cave_type *c_ptr; register inven_type *t_ptr; c_ptr = &cave[y][x]; t_ptr = &t_list[c_ptr->tptr]; if (t_ptr->tval == TV_INVIS_TRAP) { t_ptr->tval = TV_VIS_TRAP; lite_spot(y, x); } else if (t_ptr->tval == TV_SECRET_DOOR) { /* change secret door to closed door */ t_ptr->index = OBJ_CLOSED_DOOR; t_ptr->tval = object_list[OBJ_CLOSED_DOOR].tval; t_ptr->tchar = object_list[OBJ_CLOSED_DOOR].tchar; lite_spot(y, x); } } /* Searches for hidden things. -RAK- */ void search(y, x, chance) int y, x, chance; { register int i, j; register cave_type *c_ptr; register inven_type *t_ptr; register struct flags *p_ptr; bigvtype tmp_str, tmp_str2; p_ptr = &py.flags; if (p_ptr->confused > 0) chance = chance / 10; if ((p_ptr->blind > 0) || no_light()) chance = chance / 10; if (p_ptr->image > 0) chance = chance / 10; for (i = (y - 1); i <= (y + 1); i++) for (j = (x - 1); j <= (x + 1); j++) if (randint(100) < chance) /* always in_bounds here */ { c_ptr = &cave[i][j]; /* Search for hidden objects */ if (c_ptr->tptr != 0) { t_ptr = &t_list[c_ptr->tptr]; /* Trap on floor? */ if (t_ptr->tval == TV_INVIS_TRAP) { objdes(tmp_str2, t_ptr, TRUE); (void) sprintf(tmp_str,"You have found %s",tmp_str2); msg_print(tmp_str); change_trap(i, j); end_find(); } /* Secret door? */ else if (t_ptr->tval == TV_SECRET_DOOR) { msg_print("You have found a secret door."); change_trap(i, j); end_find(); } /* Chest is trapped? */ else if (t_ptr->tval == TV_CHEST) { /* mask out the treasure bits */ if ((t_ptr->flags & CH_TRAPPED) > 1) if (!known2_p(t_ptr)) { known2(t_ptr); msg_print("You have discovered a trap on the chest!"); } else msg_print("The chest is trapped!"); } } } } /* The running algorithm: -CJS- Overview: You keep moving until something interesting happens. If you are in an enclosed space, you follow corners. This is the usual corridor scheme. If you are in an open space, you go straight, but stop before entering enclosed space. This is analogous to reaching doorways. If you have enclosed space on one side only (that is, running along side a wall) stop if your wall opens out, or your open space closes in. Either case corresponds to a doorway. What happens depends on what you can really SEE. (i.e. if you have no light, then running along a dark corridor is JUST like running in a dark room.) The algorithm works equally well in corridors, rooms, mine tailings, earthquake rubble, etc, etc. These conditions are kept in static memory: find_openarea You are in the open on at least one side. find_breakleft You have a wall on the left, and will stop if it opens find_breakright You have a wall on the right, and will stop if it opens To initialize these conditions is the task of find_init. If moving from the square marked @ to the square marked . (in the two diagrams below), then two adjacent sqares on the left and the right (L and R) are considered. If either one is seen to be closed, then that side is considered to be closed. If both sides are closed, then it is an enclosed (corridor) run. LL L @. L.R RR @R Looking at more than just the immediate squares is significant. Consider the following case. A run along the corridor will stop just before entering the center point, because a choice is clearly established. Running in any of three available directions will be defined as a corridor run. Note that a minor hack is inserted to make the angled corridor entry (with one side blocked near and the other side blocked further away from the runner) work correctly. The runner moves diagonally, but then saves the previous direction as being straight into the gap. Otherwise, the tail end of the other entry would be perceived as an alternative on the next move. #.# ##.## .@... ##.## #.# Likewise, a run along a wall, and then into a doorway (two runs) will work correctly. A single run rightwards from @ will stop at 1. Another run right and down will enter the corridor and make the corner, stopping at the 2. #@ 1 ########### ###### 2 # ############# # After any move, the function area_affect is called to determine the new surroundings, and the direction of subsequent moves. It takes a location (at which the runner has just arrived) and the previous direction (from which the runner is considered to have come). Moving one square in some direction places you adjacent to three or five new squares (for straight and diagonal moves) to which you were not previously adjacent. ...! ... EG Moving from 1 to 2. .12! .1.! . means previously adjacent ...! ..2! ! means newly adjacent !!! You STOP if you can't even make the move in the chosen direction. You STOP if any of the new squares are interesting in any way: usually containing monsters or treasure. You STOP if any of the newly adjacent squares seem to be open, and you are also looking for a break on that side. (i.e. find_openarea AND find_break) You STOP if any of the newly adjacent squares do NOT seem to be open and you are in an open area, and that side was previously entirely open. Corners: If you are not in the open (i.e. you are in a corridor) and there is only one way to go in the new squares, then turn in that direction. If there are more than two new ways to go, STOP. If there are two ways to go, and those ways are separated by a square which does not seem to be open, then STOP. Otherwise, we have a potential corner. There are two new open squares, which are also adjacent. One of the new squares is diagonally located, the other is straight on (as in the diagram). We consider two more squares further out (marked below as ?). .X @.? #? If they are both seen to be closed, then it is seen that no benefit is gained from moving straight. It is a known corner. To cut the corner, go diagonally, otherwise go straight, but pretend you stepped diagonally into that next location for a full view next time. Conversely, if one of the ? squares is not seen to be closed, then there is a potential choice. We check to see whether it is a potential corner or an intersection/room entrance. If the square two spaces straight ahead, and the space marked with 'X' are both blank, then it is a potential corner and enter if find_examine is set, otherwise must stop because it is not a corner. */ /* The cycle lists the directions in anticlockwise order, for -CJS- over two complete cycles. The chome array maps a direction on to its position in the cycle. */ static int cycle[] = { 1, 2, 3, 6, 9, 8, 7, 4, 1, 2, 3, 6, 9, 8, 7, 4, 1 }; static int chome[] = { -1, 8, 9, 10, 7, -1, 11, 6, 5, 4 }; static int find_openarea, find_breakright, find_breakleft, find_prevdir; static int find_direction; /* Keep a record of which way we are going. */ void find_init(dir) int dir; { int row, col, deepleft, deepright; register int i, shortleft, shortright; row = char_row; col = char_col; if (!mmove(dir, &row, &col)) find_flag = FALSE; else { find_direction = dir; find_flag = 1; find_breakright = find_breakleft = FALSE; find_prevdir = dir; if (py.flags.blind < 1) { i = chome[dir]; deepleft = deepright = FALSE; shortright = shortleft = FALSE; if (see_wall(cycle[i+1], char_row, char_col)) { find_breakleft = TRUE; shortleft = TRUE; } else if (see_wall(cycle[i+1], row, col)) { find_breakleft = TRUE; deepleft = TRUE; } if (see_wall(cycle[i-1], char_row, char_col)) { find_breakright = TRUE; shortright = TRUE; } else if (see_wall(cycle[i-1], row, col)) { find_breakright = TRUE; deepright = TRUE; } if (find_breakleft && find_breakright) { find_openarea = FALSE; if (dir & 1) { /* a hack to allow angled corridor entry */ if (deepleft && !deepright) find_prevdir = cycle[i-1]; else if (deepright && !deepleft) find_prevdir = cycle[i+1]; } /* else if there is a wall two spaces ahead and seem to be in a corridor, then force a turn into the side corridor, must be moving straight into a corridor here */ else if (see_wall(cycle[i], row, col)) { if (shortleft && !shortright) find_prevdir = cycle[i-2]; else if (shortright && !shortleft) find_prevdir = cycle[i+2]; } } else find_openarea = TRUE; } } /* We must erase the player symbol '@' here, because sub3_move_light() does not erase the previous location of the player when in find mode and when find_prself is FALSE. The player symbol is not draw at all in this case while moving, so the only problem is on the first turn of find mode, when the initial position of the character must be erased. Hence we must do the erasure here. */ if (! light_flag && ! find_prself) print(loc_symbol(char_row, char_col), char_row, char_col); move_char(dir, TRUE); if (find_flag == FALSE) command_count = 0; } void find_run() { /* prevent infinite loops in find mode, will stop after moving 100 times */ if (find_flag++ > 100) { msg_print("You stop running to catch your breath."); end_find(); } else move_char(find_direction, TRUE); } /* Switch off the run flag - and get the light correct. -CJS- */ void end_find() { if (find_flag) { find_flag = FALSE; move_light(char_row, char_col, char_row, char_col); } } /* Do we see a wall? Used in running. -CJS- */ static int see_wall(dir, y, x) int dir, y, x; { char c; if (!mmove(dir, &y, &x)) /* check to see if movement there possible */ return TRUE; #ifdef MSDOS else if ((c = loc_symbol(y, x)) == wallsym || c == '%') #else #ifdef ATARI_ST else if ((c = loc_symbol(y, x)) == (unsigned char)240 || c == '%') #else else if ((c = loc_symbol(y, x)) == '#' || c == '%') #endif #endif return TRUE; else return FALSE; } /* Do we see anything? Used in running. -CJS- */ static int see_nothing(dir, y, x) int dir, y, x; { if (!mmove(dir, &y, &x)) /* check to see if movement there possible */ return FALSE; else if (loc_symbol(y, x) == ' ') return TRUE; else return FALSE; } /* Determine the next direction for a run, or if we should stop. -CJS- */ void area_affect(dir, y, x) int dir, y, x; { int newdir, t, inv, check_dir, row, col; register int i, max, option, option2; register cave_type *c_ptr; if (py.flags.blind < 1) { option = 0; option2 = 0; dir = find_prevdir; max = (dir & 1) + 1; /* Look at every newly adjacent square. */ for(i = -max; i <= max; i++) { newdir = cycle[chome[dir]+i]; row = y; col = x; if (mmove(newdir, &row, &col)) { /* Objects player can see (Including doors?) cause a stop. */ c_ptr = &cave[row][col]; if (player_light || c_ptr->tl || c_ptr->pl || c_ptr->fm) { if (c_ptr->tptr != 0) { t = t_list[c_ptr->tptr].tval; if (t != TV_INVIS_TRAP && t != TV_SECRET_DOOR && (t != TV_OPEN_DOOR || !find_ignore_doors)) { end_find(); return; } } /* Also Creatures */ /* the monster should be visible since update_mon() checks for the special case of being in find mode */ if (c_ptr->cptr > 1 && m_list[c_ptr->cptr].ml) { end_find(); return; } inv = FALSE; } else inv = TRUE; /* Square unseen. Treat as open. */ if (c_ptr->fval <= MAX_OPEN_SPACE || inv) { if (find_openarea) { /* Have we found a break? */ if (i < 0) { if (find_breakright) { end_find(); return; } } else if (i > 0) { if (find_breakleft) { end_find(); return; } } } else if (option == 0) option = newdir; /* The first new direction. */ else if (option2 != 0) { end_find(); /* Three new directions. STOP. */ return; } else if (option != cycle[chome[dir]+i-1]) { end_find(); /* If not adjacent to prev, STOP */ return; } else { /* Two adjacent choices. Make option2 the diagonal, and remember the other diagonal adjacent to the first option. */ if ((newdir & 1) == 1) { check_dir = cycle[chome[dir]+i-2]; option2 = newdir; } else { check_dir = cycle[chome[dir]+i+1]; option2 = option; option = newdir; } } } else if (find_openarea) { /* We see an obstacle. In open area, STOP if on a side previously open. */ if (i < 0) { if (find_breakleft) { end_find(); return; } find_breakright = TRUE; } else if (i > 0) { if (find_breakright) { end_find(); return; } find_breakleft = TRUE; } } } } if (find_openarea == FALSE) { /* choose a direction. */ if (option2 == 0 || (find_examine && !find_cut)) { /* There is only one option, or if two, then we always examine potential corners and never cur known corners, so you step into the straight option. */ if (option != 0) find_direction = option; if (option2 == 0) find_prevdir = option; else find_prevdir = option2; } else { /* Two options! */ row = y; col = x; (void) mmove(option, &row, &col); if (!see_wall(option, row, col) || !see_wall(check_dir, row, col)) { /* Don't see that it is closed off. This could be a potential corner or an intersection. */ if (find_examine && see_nothing(option, row, col) && see_nothing(option2, row, col)) /* Can not see anything ahead and in the direction we are turning, assume that it is a potential corner. */ { find_direction = option; find_prevdir = option2; } else /* STOP: we are next to an intersection or a room */ end_find(); } else if (find_cut) { /* This corner is seen to be enclosed; we cut the corner. */ find_direction = option2; find_prevdir = option2; } else { /* This corner is seen to be enclosed, and we deliberately go the long way. */ find_direction = option; find_prevdir = option2; } } } } } /* AC gets worse -RAK- */ /* Note: This routine affects magical AC bonuses so that stores */ /* can detect the damage. */ int minus_ac(typ_dam) int32u typ_dam; { register int i, j; int tmp[6], minus; register inven_type *i_ptr; bigvtype out_val, tmp_str; i = 0; if (inventory[INVEN_BODY].tval != TV_NOTHING) { tmp[i] = INVEN_BODY; i++; } if (inventory[INVEN_ARM].tval != TV_NOTHING) { tmp[i] = INVEN_ARM; i++; } if (inventory[INVEN_OUTER].tval != TV_NOTHING) { tmp[i] = INVEN_OUTER; i++; } if (inventory[INVEN_HANDS].tval != TV_NOTHING) { tmp[i] = INVEN_HANDS; i++; } if (inventory[INVEN_HEAD].tval != TV_NOTHING) { tmp[i] = INVEN_HEAD; i++; } /* also affect boots */ if (inventory[INVEN_FEET].tval != TV_NOTHING) { tmp[i] = INVEN_FEET; i++; } minus = FALSE; if (i > 0) { j = tmp[randint(i) - 1]; i_ptr = &inventory[j]; if (i_ptr->flags & typ_dam) { objdes(tmp_str, &inventory[j], FALSE); (void) sprintf(out_val, "Your %s resists damage!", tmp_str); msg_print(out_val); minus = TRUE; } else if ((i_ptr->ac+i_ptr->toac) > 0) { objdes(tmp_str, &inventory[j], FALSE); (void) sprintf(out_val, "Your %s is damaged!", tmp_str); msg_print(out_val); i_ptr->toac--; calc_bonuses(); minus = TRUE; } } return(minus); } /* Corrode the unsuspecting person's armor -RAK- */ void corrode_gas(kb_str) char *kb_str; { #ifdef ATARIST_MWC int32u holder; #endif #ifdef ATARIST_MWC if (!minus_ac((int32u) (holder = TR_RES_ACID))) #else if (!minus_ac((int32u) TR_RES_ACID)) #endif take_hit(randint(8), kb_str); if (inven_damage(set_corrodes, 5) > 0) msg_print("There is an acrid smell coming from your pack."); } /* Poison gas the idiot. -RAK- */ void poison_gas(dam, kb_str) int dam; char *kb_str; { take_hit(dam, kb_str); py.flags.poisoned += 12 + randint(dam); } /* Burn the fool up. -RAK- */ void fire_dam(dam, kb_str) int dam; char *kb_str; { if (py.flags.fire_resist) dam = dam / 3; if (py.flags.resist_heat > 0) dam = dam / 3; take_hit(dam, kb_str); if (inven_damage(set_flammable, 3) > 0) msg_print("There is smoke coming from your pack!"); } /* Freeze him to death. -RAK- */ void cold_dam(dam, kb_str) int dam; char *kb_str; { if (py.flags.cold_resist) dam = dam / 3; if (py.flags.resist_cold > 0) dam = dam / 3; take_hit(dam, kb_str); if (inven_damage(set_frost_destroy, 5) > 0) msg_print("Something shatters inside your pack!"); } /* Lightning bolt the sucker away. -RAK- */ void light_dam(dam, kb_str) int dam; char *kb_str; { if (py.flags.lght_resist) take_hit((dam / 3), kb_str); else take_hit(dam, kb_str); if (inven_damage(set_lightning_destroy, 3) > 0) msg_print("There are sparks coming from your pack!"); } /* Throw acid on the hapless victim -RAK- */ void acid_dam(dam, kb_str) int dam; char *kb_str; { register int flag; #ifdef ATARIST_MWC int32u holder; #endif flag = 0; #ifdef ATARIST_MWC if (minus_ac((int32u) (holder = TR_RES_ACID))) #else if (minus_ac((int32u) TR_RES_ACID)) #endif flag = 1; if (py.flags.acid_resist) flag += 2; take_hit (dam / (flag + 1), kb_str); if (inven_damage(set_acid_affect, 3) > 0) msg_print("There is an acrid smell coming from your pack!"); } moria-5.6.debian.1/source/tables.c0000644000175000017500000002601011074756544015115 0ustar pjbpjb/* source/tables.c: store/attack/RNG/etc tables and variables Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include "config.h" #include "constant.h" #include "types.h" #ifdef MORIA_HOU /* Operating hours for Moria -RAK- */ /* X = Open; . = Closed */ char days[7][29] = { "SUN:XXXXXXXXXXXXXXXXXXXXXXXX", "MON:XXXXXXXX.........XXXXXXX", "TUE:XXXXXXXX.........XXXXXXX", "WED:XXXXXXXX.........XXXXXXX", "THU:XXXXXXXX.........XXXXXXX", "FRI:XXXXXXXX.........XXXXXXX", "SAT:XXXXXXXXXXXXXXXXXXXXXXXX" }; #endif #ifdef MAC store_type *store; #else store_type store[MAX_STORES]; #endif /* Store owners have different characteristics for pricing and haggling*/ /* Note: Store owners should be added in groups, one for each store */ #ifdef MACGAME owner_type *owners; #else owner_type owners[MAX_OWNERS] = { {"Erick the Honest (Human) General Store", 250, 175, 108, 4, 0, 12}, {"Mauglin the Grumpy (Dwarf) Armory" , 32000, 200, 112, 4, 5, 5}, {"Arndal Beast-Slayer (Half-Elf) Weaponsmith" , 10000, 185, 110, 5, 1, 8}, {"Hardblow the Humble (Human) Temple" , 3500, 175, 109, 6, 0, 15}, {"Ga-nat the Greedy (Gnome) Alchemist" , 12000, 220, 115, 4, 4, 9}, {"Valeria Starshine (Elf) Magic Shop" , 32000, 175, 110, 5, 2, 11}, {"Andy the Friendly (Halfling) General Store", 200, 170, 108, 5, 3, 15}, {"Darg-Low the Grim (Human) Armory" , 10000, 190, 111, 4, 0, 9}, {"Oglign Dragon-Slayer (Dwarf) Weaponsmith" , 32000, 195, 112, 4, 5, 8}, {"Gunnar the Paladin (Human) Temple" , 5000, 185, 110, 5, 0, 23}, {"Mauser the Chemist (Half-Elf) Alchemist" , 10000, 190, 111, 5, 1, 8}, {"Gopher the Great! (Gnome) Magic Shop" , 20000, 215, 113, 6, 4, 10}, {"Lyar-el the Comely (Elf) General Store", 300, 165, 107, 6, 2, 18}, {"Mauglim the Horrible (Half-Orc) Armory" , 3000, 200, 113, 5, 6, 9}, {"Ithyl-Mak the Beastly (Half-Troll) Weaponsmith" , 3000, 210, 115, 6, 7, 8}, {"Delilah the Pure (Half-Elf) Temple" , 25000, 180, 107, 6, 1, 20}, {"Wizzle the Chaotic (Halfling) Alchemist" , 10000, 190, 110, 6, 3, 8}, {"Inglorian the Mage (Human?) Magic Shop" , 32000, 200, 110, 7, 0, 10} }; #endif /* Buying and selling adjustments for character race VS store */ /* owner race */ int8u rgold_adj[MAX_RACES][MAX_RACES] = { /* Hum, HfE, Elf, Hal, Gno, Dwa, HfO, HfT*/ /*Human */ { 100, 105, 105, 110, 113, 115, 120, 125}, /*Half-Elf */ { 110, 100, 100, 105, 110, 120, 125, 130}, /*Elf */ { 110, 105, 100, 105, 110, 120, 125, 130}, /*Halfling */ { 115, 110, 105, 95, 105, 110, 115, 130}, /*Gnome */ { 115, 115, 110, 105, 95, 110, 115, 130}, /*Dwarf */ { 115, 120, 120, 110, 110, 95, 125, 135}, /*Half-Orc */ { 115, 120, 125, 115, 115, 130, 110, 115}, /*Half-Troll */ { 110, 115, 115, 110, 110, 130, 110, 110} }; /* object_list[] index of objects that may appear in the store */ int16u store_choice[MAX_STORES][STORE_CHOICES] = { /* General Store */ {366,365,364,84,84,365,123,366,365,350,349,348,347,346,346,345,345,345, 344,344,344,344,344,344,344,344}, /* Armory */ {94,95,96,109,103,104,105,106,110,111,112,114,116,124,125,126,127,129,103, 104,124,125,91,92,95,96}, /* Weaponsmith */ {29,30,34,37,45,49,57,58,59,65,67,68,73,74,75,77,79,80,81,83,29,30,80,83, 80,83}, /* Temple */ {322,323,324,325,180,180,233,237,240,241,361,362,57,58,59,260,358,359,265, 237,237,240,240,241,323,359}, /* Alchemy shop */ {173,174,175,351,351,352,353,354,355,356,357,206,227,230,236,252,253,352, 353,354,355,356,359,363,359,359}, /* Magic-User store*/ {318,141,142,153,164,167,168,140,319,320,320,321,269,270,282,286,287,292, 293,294,295,308,269,290,319,282} }; #ifndef MAC /* MPW doesn't seem to handle this very well, so replace store_buy array with a function call on mac */ /* functions defined in sets.c */ extern int general_store(), armory(), weaponsmith(), temple(), alchemist(), magic_shop(); /* Each store will buy only certain items, based on TVAL */ int (*store_buy[MAX_STORES])() = { general_store, armory, weaponsmith, temple, alchemist, magic_shop}; #endif /* Following are arrays for descriptive pieces */ #ifdef MACGAME char **colors; char **mushrooms; char **woods; char **metals; char **rocks; char **amulets; char **syllables; #else char *colors[MAX_COLORS] = { /* Do not move the first three */ "Icky Green", "Light Brown", "Clear", "Azure","Blue","Blue Speckled","Black","Brown","Brown Speckled","Bubbling", "Chartreuse","Cloudy","Copper Speckled","Crimson","Cyan","Dark Blue", "Dark Green","Dark Red","Gold Speckled","Green","Green Speckled","Grey", "Grey Speckled","Hazy","Indigo","Light Blue","Light Green","Magenta", "Metallic Blue","Metallic Red","Metallic Green","Metallic Purple","Misty", "Orange","Orange Speckled","Pink","Pink Speckled","Puce","Purple", "Purple Speckled","Red","Red Speckled","Silver Speckled","Smoky", "Tangerine","Violet","Vermilion","White","Yellow" }; char *mushrooms[MAX_MUSH] = { "Blue","Black","Black Spotted","Brown","Dark Blue","Dark Green","Dark Red", "Ecru","Furry","Green","Grey","Light Blue","Light Green","Plaid","Red", "Slimy","Tan","White","White Spotted","Wooden","Wrinkled","Yellow", }; char *woods[MAX_WOODS] = { "Aspen","Balsa","Banyan","Birch","Cedar","Cottonwood","Cypress","Dogwood", "Elm","Eucalyptus","Hemlock","Hickory","Ironwood","Locust","Mahogany", "Maple","Mulberry","Oak","Pine","Redwood","Rosewood","Spruce","Sycamore", "Teak","Walnut", }; char *metals[MAX_METALS] = { "Aluminum","Cast Iron","Chromium","Copper","Gold","Iron","Magnesium", "Molybdenum","Nickel","Rusty","Silver","Steel","Tin","Titanium","Tungsten", "Zirconium","Zinc","Aluminum-Plated","Copper-Plated","Gold-Plated", "Nickel-Plated","Silver-Plated","Steel-Plated","Tin-Plated","Zinc-Plated" }; char *rocks[MAX_ROCKS] = { "Alexandrite","Amethyst","Aquamarine","Azurite","Beryl","Bloodstone", "Calcite","Carnelian","Corundum","Diamond","Emerald","Fluorite","Garnet", "Granite","Jade","Jasper","Lapis Lazuli","Malachite","Marble","Moonstone", "Onyx","Opal","Pearl","Quartz","Quartzite","Rhodonite","Ruby","Sapphire", "Tiger Eye","Topaz","Turquoise","Zircon" }; char *amulets[MAX_AMULETS] = { "Amber","Driftwood","Coral","Agate","Ivory","Obsidian", "Bone","Brass","Bronze","Pewter","Tortoise Shell" }; char *syllables[MAX_SYLLABLES] = { "a","ab","ag","aks","ala","an","ankh","app", "arg","arze","ash","aus","ban","bar","bat","bek", "bie","bin","bit","bjor","blu","bot","bu", "byt","comp","con","cos","cre","dalf","dan", "den","doe","dok","eep","el","eng","er","ere","erk", "esh","evs","fa","fid","for","fri","fu","gan", "gar","glen","gop","gre","ha","he","hyd","i", "ing","ion","ip","ish","it","ite","iv","jo", "kho","kli","klis","la","lech","man","mar", "me","mi","mic","mik","mon","mung","mur","nej", "nelg","nep","ner","nes","nis","nih","nin","o", "od","ood","org","orn","ox","oxy","pay","pet", "ple","plu","po","pot","prok","re","rea","rhov", "ri","ro","rog","rok","rol","sa","san","sat", "see","sef","seh","shu","ski","sna","sne","snik", "sno","so","sol","sri","sta","sun","ta","tab", "tem","ther","ti","tox","trol","tue","turs","u", "ulk","um","un","uni","ur","val","viv","vly", "vom","wah","wed","werg","wex","whon","wun","x", "yerg","yp","zun" }; #endif /* used to calculate the number of blows the player gets in combat */ int8u blows_table[7][6] = { /* STR/W: 9 18 67 107 117 118 : DEX */ /* <2 */ { 1, 1, 1, 1, 1, 1 }, /* <3 */ { 1, 1, 1, 1, 2, 2 }, /* <4 */ { 1, 1, 1, 2, 2, 3 }, /* <5 */ { 1, 1, 2, 2, 3, 3 }, /* <7 */ { 1, 2, 2, 3, 3, 4 }, /* <9 */ { 1, 2, 2, 3, 4, 4 }, /* >9 */ { 2, 2, 3, 3, 4, 4 } }; /* this table is used to generate a psuedo-normal distribution. See the function randnor() in misc1.c, this is much faster than calling transcendental function to calculate a true normal distribution */ int16u normal_table[NORMAL_TABLE_SIZE] = { 206, 613, 1022, 1430, 1838, 2245, 2652, 3058, 3463, 3867, 4271, 4673, 5075, 5475, 5874, 6271, 6667, 7061, 7454, 7845, 8234, 8621, 9006, 9389, 9770, 10148, 10524, 10898, 11269, 11638, 12004, 12367, 12727, 13085, 13440, 13792, 14140, 14486, 14828, 15168, 15504, 15836, 16166, 16492, 16814, 17133, 17449, 17761, 18069, 18374, 18675, 18972, 19266, 19556, 19842, 20124, 20403, 20678, 20949, 21216, 21479, 21738, 21994, 22245, 22493, 22737, 22977, 23213, 23446, 23674, 23899, 24120, 24336, 24550, 24759, 24965, 25166, 25365, 25559, 25750, 25937, 26120, 26300, 26476, 26649, 26818, 26983, 27146, 27304, 27460, 27612, 27760, 27906, 28048, 28187, 28323, 28455, 28585, 28711, 28835, 28955, 29073, 29188, 29299, 29409, 29515, 29619, 29720, 29818, 29914, 30007, 30098, 30186, 30272, 30356, 30437, 30516, 30593, 30668, 30740, 30810, 30879, 30945, 31010, 31072, 31133, 31192, 31249, 31304, 31358, 31410, 31460, 31509, 31556, 31601, 31646, 31688, 31730, 31770, 31808, 31846, 31882, 31917, 31950, 31983, 32014, 32044, 32074, 32102, 32129, 32155, 32180, 32205, 32228, 32251, 32273, 32294, 32314, 32333, 32352, 32370, 32387, 32404, 32420, 32435, 32450, 32464, 32477, 32490, 32503, 32515, 32526, 32537, 32548, 32558, 32568, 32577, 32586, 32595, 32603, 32611, 32618, 32625, 32632, 32639, 32645, 32651, 32657, 32662, 32667, 32672, 32677, 32682, 32686, 32690, 32694, 32698, 32702, 32705, 32708, 32711, 32714, 32717, 32720, 32722, 32725, 32727, 32729, 32731, 32733, 32735, 32737, 32739, 32740, 32742, 32743, 32745, 32746, 32747, 32748, 32749, 32750, 32751, 32752, 32753, 32754, 32755, 32756, 32757, 32757, 32758, 32758, 32759, 32760, 32760, 32761, 32761, 32761, 32762, 32762, 32763, 32763, 32763, 32764, 32764, 32764, 32764, 32765, 32765, 32765, 32765, 32766, 32766, 32766, 32766, 32766, }; moria-5.6.debian.1/source/misc1.c0000644000175000017500000006052111074756544014664 0ustar pjbpjb/* source/misc1.c: misc utility and initialization code, magic objects code Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #include #ifdef Pyramid #include #else #include #endif #if !defined(GEMDOS) && !defined(MAC) && !defined(AMIGA) #ifndef VMS #include #else #include #endif #endif #if !defined(ATARIST_MWC) && !defined(MAC) && !defined(VMS) && !defined(AMIGA) long time(); #endif struct tm *localtime(); #if defined(LINT_ARGS) static void compact_objects(void); #endif /* gets a new random seed for the random number generator */ void init_seeds(seed) int32u seed; { register int32u clock_var; if (seed == 0) #ifdef MAC clock_var = time((time_t *)0); #else clock_var = time((long *)0); #endif else clock_var = seed; randes_seed = (int32) clock_var; clock_var += 8762; town_seed = (int32) clock_var; clock_var += 113452L; set_rnd_seed(clock_var); /* make it a little more random */ for (clock_var = randint(100); clock_var != 0; clock_var--) (void) rnd(); } /* holds the previous rnd state */ static int32u old_seed; /* change to different random number generator state */ void set_seed(seed) int32u seed; { old_seed = get_rnd_seed (); /* want reproducible state here */ set_rnd_seed (seed); } /* restore the normal random generator state */ void reset_seed() { set_rnd_seed (old_seed); } /* Check the day-time strings to see if open -RAK- */ int check_time() { #ifdef MORIA_HOU long clock_var; register struct tm *tp; #ifdef MAC clock_var = time((time_t *)0); #else clock_var = time((long *)0); #endif tp = localtime(&clock_var); if (days[tp->tm_wday][tp->tm_hour+4] == 'X') return TRUE; else return FALSE; #else return TRUE; #endif } /* Generates a random integer x where 1<=X<=MAXVAL -RAK- */ int randint(maxval) int maxval; { register long randval; randval = rnd (); return ((int)(randval % maxval) + 1); } /* Generates a random integer number of NORMAL distribution -RAK-*/ int randnor(mean, stand) int mean, stand; { register int tmp, offset, low, iindex, high; #if 0 /* alternate randnor code, slower but much smaller since no table */ /* 2 per 1,000,000 will be > 4*SD, max is 5*SD */ tmp = damroll(8, 99); /* mean 400, SD 81 */ tmp = (tmp - 400) * stand / 81; return tmp + mean; #endif tmp = randint(MAX_SHORT); /* off scale, assign random value between 4 and 5 times SD */ if (tmp == MAX_SHORT) { offset = 4 * stand + randint(stand); /* one half are negative */ if (randint(2) == 1) offset = -offset; return mean + offset; } /* binary search normal normal_table to get index that matches tmp */ /* this takes up to 8 iterations */ low = 0; iindex = NORMAL_TABLE_SIZE >> 1; high = NORMAL_TABLE_SIZE; while (TRUE) { if ((normal_table[iindex] == tmp) || (high == (low+1))) break; if (normal_table[iindex] > tmp) { high = iindex; iindex = low + ((iindex - low) >> 1); } else { low = iindex; iindex = iindex + ((high - iindex) >> 1); } } /* might end up one below target, check that here */ if (normal_table[iindex] < tmp) iindex = iindex + 1; /* normal_table is based on SD of 64, so adjust the index value here, round the half way case up */ offset = ((stand * iindex) + (NORMAL_TABLE_SD >> 1)) / NORMAL_TABLE_SD; /* one half should be negative */ if (randint(2) == 1) offset = -offset; return mean + offset; } /* Returns position of first set bit -RAK- */ /* and clears that bit */ int bit_pos(test) int32u *test; { register int i; register int32u mask = 0x1; for (i = 0; i < sizeof(*test)*8; i++) { if (*test & mask) { *test &= ~mask; return(i); } mask <<= 1; } /* no one bits found */ return(-1); } /* Checks a co-ordinate for in bounds status -RAK- */ int in_bounds(y, x) int y, x; { if ((y > 0) && (y < cur_height-1) && (x > 0) && (x < cur_width-1)) return(TRUE); else return(FALSE); } /* Calculates current boundaries -RAK- */ void panel_bounds() { panel_row_min = panel_row*(SCREEN_HEIGHT/2); panel_row_max = panel_row_min + SCREEN_HEIGHT - 1; panel_row_prt = panel_row_min - 1; panel_col_min = panel_col*(SCREEN_WIDTH/2); panel_col_max = panel_col_min + SCREEN_WIDTH - 1; panel_col_prt = panel_col_min - 13; } /* Given an row (y) and col (x), this routine detects -RAK- */ /* when a move off the screen has occurred and figures new borders. Force forcses the panel bounds to be recalculated, useful for 'W'here. */ int get_panel(y, x, force) int y, x, force; { register int prow, pcol; register int panel; prow = panel_row; pcol = panel_col; if (force || (y < panel_row_min + 2) || (y > panel_row_max - 2)) { prow = ((y - SCREEN_HEIGHT/4)/(SCREEN_HEIGHT/2)); if (prow > max_panel_rows) prow = max_panel_rows; else if (prow < 0) prow = 0; } if (force || (x < panel_col_min + 3) || (x > panel_col_max - 3)) { pcol = ((x - SCREEN_WIDTH/4)/(SCREEN_WIDTH/2)); if (pcol > max_panel_cols) pcol = max_panel_cols; else if (pcol < 0) pcol = 0; } if ((prow != panel_row) || (pcol != panel_col)) { panel_row = prow; panel_col = pcol; panel_bounds(); panel = TRUE; /* stop movement if any */ if (find_bound) end_find(); } else panel = FALSE; return(panel); } /* Tests a given point to see if it is within the screen -RAK- */ /* boundaries. */ int panel_contains(y, x) register int y, x; { if ((y >= panel_row_min) && (y <= panel_row_max) && (x >= panel_col_min) && (x <= panel_col_max)) return (TRUE); else return (FALSE); } /* Distance between two points -RAK- */ int distance(y1, x1, y2, x2) int y1, x1, y2, x2; { register int dy, dx; dy = y1 - y2; if (dy < 0) dy = -dy; dx = x1 - x2; if (dx < 0) dx = -dx; return ((((dy + dx) << 1) - (dy > dx ? dx : dy)) >> 1); } /* Checks points north, south, east, and west for a wall -RAK- */ /* note that y,x is always in_bounds(), i.e. 0 < y < cur_height-1, and 0 < x < cur_width-1 */ int next_to_walls(y, x) register int y, x; { register int i; register cave_type *c_ptr; i = 0; c_ptr = &cave[y-1][x]; if (c_ptr->fval >= MIN_CAVE_WALL) i++; c_ptr = &cave[y+1][x]; if (c_ptr->fval >= MIN_CAVE_WALL) i++; c_ptr = &cave[y][x-1]; if (c_ptr->fval >= MIN_CAVE_WALL) i++; c_ptr = &cave[y][x+1]; if (c_ptr->fval >= MIN_CAVE_WALL) i++; return(i); } /* Checks all adjacent spots for corridors -RAK- */ /* note that y, x is always in_bounds(), hence no need to check that j, k are in_bounds(), even if they are 0 or cur_x-1 is still works */ int next_to_corr(y, x) register int y, x; { register int k, j, i; register cave_type *c_ptr; i = 0; for (j = y - 1; j <= (y + 1); j++) for (k = x - 1; k <= (x + 1); k++) { c_ptr = &cave[j][k]; /* should fail if there is already a door present */ if (c_ptr->fval == CORR_FLOOR && (c_ptr->tptr == 0 || t_list[c_ptr->tptr].tval < TV_MIN_DOORS)) i++; } return(i); } /* generates damage for 2d6 style dice rolls */ int damroll(num, sides) int num, sides; { register int i, sum = 0; for (i = 0; i < num; i++) sum += randint(sides); return(sum); } int pdamroll(array) int8u *array; { return damroll((int)array[0], (int)array[1]); } /* A simple, fast, integer-based line-of-sight algorithm. By Joseph Hall, 4116 Brewster Drive, Raleigh NC 27606. Email to jnh@ecemwl.ncsu.edu. Returns TRUE if a line of sight can be traced from x0, y0 to x1, y1. The LOS begins at the center of the tile [x0, y0] and ends at the center of the tile [x1, y1]. If los() is to return TRUE, all of the tiles this line passes through must be transparent, WITH THE EXCEPTIONS of the starting and ending tiles. We don't consider the line to be "passing through" a tile if it only passes across one corner of that tile. */ /* Because this function uses (short) ints for all calculations, overflow may occur if deltaX and deltaY exceed 90. */ int los(fromY, fromX, toY, toX) int fromY, fromX, toY, toX; { register int tmp, deltaX, deltaY; deltaX = toX - fromX; deltaY = toY - fromY; /* Adjacent? */ if ((deltaX < 2) && (deltaX > -2) && (deltaY < 2) && (deltaY > -2)) return TRUE; /* Handle the cases where deltaX or deltaY == 0. */ if (deltaX == 0) { register int p_y; /* y position -- loop variable */ if (deltaY < 0) { tmp = fromY; fromY = toY; toY = tmp; } for (p_y = fromY + 1; p_y < toY; p_y++) if (cave[p_y][fromX].fval >= MIN_CLOSED_SPACE) return FALSE; return TRUE; } else if (deltaY == 0) { register int px; /* x position -- loop variable */ if (deltaX < 0) { tmp = fromX; fromX = toX; toX = tmp; } for (px = fromX + 1; px < toX; px++) if (cave[fromY][px].fval >= MIN_CLOSED_SPACE) return FALSE; return TRUE; } /* Now, we've eliminated all the degenerate cases. In the computations below, dy (or dx) and m are multiplied by a scale factor, scale = abs(deltaX * deltaY * 2), so that we can use integer arithmetic. */ { register int px, /* x position */ p_y, /* y position */ scale2; /* above scale factor / 2 */ int scale, /* above scale factor */ xSign, /* sign of deltaX */ ySign, /* sign of deltaY */ m; /* slope or 1/slope of LOS */ scale2 = abs(deltaX * deltaY); scale = scale2 << 1; xSign = (deltaX < 0) ? -1 : 1; ySign = (deltaY < 0) ? -1 : 1; /* Travel from one end of the line to the other, oriented along the longer axis. */ if (abs(deltaX) >= abs(deltaY)) { register int dy; /* "fractional" y position */ /* We start at the border between the first and second tiles, where the y offset = .5 * slope. Remember the scale factor. We have: m = deltaY / deltaX * 2 * (deltaY * deltaX) = 2 * deltaY * deltaY. */ dy = deltaY * deltaY; m = dy << 1; px = fromX + xSign; /* Consider the special case where slope == 1. */ if (dy == scale2) { p_y = fromY + ySign; dy -= scale; } else p_y = fromY; while (toX - px) { if (cave[p_y][px].fval >= MIN_CLOSED_SPACE) return FALSE; dy += m; if (dy < scale2) px += xSign; else if (dy > scale2) { p_y += ySign; if (cave[p_y][px].fval >= MIN_CLOSED_SPACE) return FALSE; px += xSign; dy -= scale; } else { /* This is the case, dy == scale2, where the LOS exactly meets the corner of a tile. */ px += xSign; p_y += ySign; dy -= scale; } } return TRUE; } else { register int dx; /* "fractional" x position */ dx = deltaX * deltaX; m = dx << 1; p_y = fromY + ySign; if (dx == scale2) { px = fromX + xSign; dx -= scale; } else px = fromX; while (toY - p_y) { if (cave[p_y][px].fval >= MIN_CLOSED_SPACE) return FALSE; dx += m; if (dx < scale2) p_y += ySign; else if (dx > scale2) { px += xSign; if (cave[p_y][px].fval >= MIN_CLOSED_SPACE) return FALSE; p_y += ySign; dx -= scale; } else { px += xSign; p_y += ySign; dx -= scale; } } return TRUE; } } } /* Returns symbol for given row, column -RAK- */ unsigned char loc_symbol(y, x) int y, x; { register cave_type *cave_ptr; register struct flags *f_ptr; cave_ptr = &cave[y][x]; f_ptr = &py.flags; if ((cave_ptr->cptr == 1) && (!find_flag || find_prself)) return '@'; else if (f_ptr->status & PY_BLIND) return ' '; else if ((f_ptr->image > 0) && (randint (12) == 1)) return randint (95) + 31; else if ((cave_ptr->cptr > 1) && (m_list[cave_ptr->cptr].ml)) return c_list[m_list[cave_ptr->cptr].mptr].cchar; else if (!cave_ptr->pl && !cave_ptr->tl && !cave_ptr->fm) return ' '; else if ((cave_ptr->tptr != 0) && (t_list[cave_ptr->tptr].tval != TV_INVIS_TRAP)) return t_list[cave_ptr->tptr].tchar; else if (cave_ptr->fval <= MAX_CAVE_FLOOR) { #ifdef MSDOS return floorsym; #else return '.'; #endif } else if (cave_ptr->fval == GRANITE_WALL || cave_ptr->fval == BOUNDARY_WALL || highlight_seams == FALSE) { #ifdef MSDOS return wallsym; #else #ifndef ATARI_ST return '#'; #else return (unsigned char)240; #endif #endif } else /* Originally set highlight bit, but that is not portable, now use the percent sign instead. */ { return '%'; } } /* Tests a spot for light or field mark status -RAK- */ int test_light(y, x) int y, x; { register cave_type *cave_ptr; cave_ptr = &cave[y][x]; if (cave_ptr->pl || cave_ptr->tl || cave_ptr->fm) return(TRUE); else return(FALSE); } /* Prints the map of the dungeon -RAK- */ void prt_map() { register int i, j, k; register unsigned char tmp_char; k = 0; for (i = panel_row_min; i <= panel_row_max; i++) /* Top to bottom */ { k++; erase_line (k, 13); for (j = panel_col_min; j <= panel_col_max; j++) /* Left to right */ { tmp_char = loc_symbol(i, j); if (tmp_char != ' ') print(tmp_char, i, j); } } } /* Compact monsters -RAK- */ /* Return TRUE if any monsters were deleted, FALSE if could not delete any monsters. */ int compact_monsters() { register int i; int cur_dis, delete_any; register monster_type *mon_ptr; #ifdef ATARIST_MWC int32 holder; #endif msg_print("Compacting monsters..."); cur_dis = 66; delete_any = FALSE; do { for (i = mfptr - 1; i >= MIN_MONIX; i--) { mon_ptr = &m_list[i]; if ((cur_dis < mon_ptr->cdis) && (randint(3) == 1)) { /* Never compact away the Balrog!! */ #ifdef ATARIST_MWC if (c_list[mon_ptr->mptr].cmove & (holder = CM_WIN)) #else if (c_list[mon_ptr->mptr].cmove & CM_WIN) #endif /* Do nothing */ ; /* in case this is called from within creatures(), this is a horrible hack, the m_list/creatures() code needs to be rewritten */ else if (hack_monptr < i) { delete_monster(i); delete_any = TRUE; } else /* fix1_delete_monster() does not decrement mfptr, so don't set delete_any if this was called */ fix1_delete_monster(i); } } if (!delete_any) { cur_dis -= 6; /* Can't delete any monsters, return failure. */ if (cur_dis < 0) return FALSE; } } while (!delete_any); return TRUE; } /* Add to the players food time -RAK- */ void add_food(num) int num; { register struct flags *p_ptr; register int extra, penalty; p_ptr = &py.flags; if (p_ptr->food < 0) p_ptr->food = 0; p_ptr->food += num; if (p_ptr->food > PLAYER_FOOD_MAX) { msg_print("You are bloated from overeating."); /* Calculate how much of num is responsible for the bloating. Give the player food credit for 1/50, and slow him for that many turns also. */ extra = p_ptr->food - PLAYER_FOOD_MAX; if (extra > num) extra = num; penalty = extra / 50; p_ptr->slow += penalty; if (extra == num) p_ptr->food = p_ptr->food - num + penalty; else p_ptr->food = PLAYER_FOOD_MAX + penalty; } else if (p_ptr->food > PLAYER_FOOD_FULL) msg_print("You are full."); } /* Returns a pointer to next free space -RAK- */ /* Returns -1 if could not allocate a monster. */ int popm() { if (mfptr == MAX_MALLOC) { if (! compact_monsters()) return -1; } return (mfptr++); } /* Gives Max hit points -RAK- */ int max_hp(array) int8u *array; { return(array[0] * array[1]); } /* Places a monster at given location -RAK- */ int place_monster(y, x, z, slp) register int y, x, z; int slp; { register int cur_pos; register monster_type *mon_ptr; cur_pos = popm(); if (cur_pos == -1) return FALSE; mon_ptr = &m_list[cur_pos]; mon_ptr->fy = y; mon_ptr->fx = x; mon_ptr->mptr = z; if (c_list[z].cdefense & CD_MAX_HP) mon_ptr->hp = max_hp(c_list[z].hd); else mon_ptr->hp = pdamroll(c_list[z].hd); /* the c_list speed value is 10 greater, so that it can be a int8u */ mon_ptr->cspeed = c_list[z].speed - 10 + py.flags.speed; mon_ptr->stunned = 0; mon_ptr->cdis = distance(char_row, char_col,y,x); mon_ptr->ml = FALSE; cave[y][x].cptr = cur_pos; if (slp) { if (c_list[z].sleep == 0) mon_ptr->csleep = 0; else mon_ptr->csleep = (c_list[z].sleep * 2) + randint((int)c_list[z].sleep*10); } else mon_ptr->csleep = 0; return TRUE; } /* Places a monster at given location -RAK- */ void place_win_monster() { register int y, x, cur_pos; register monster_type *mon_ptr; if (!total_winner) { cur_pos = popm(); /* Check for case where could not allocate space for the win monster, this should never happen. */ if (cur_pos == -1) abort(); mon_ptr = &m_list[cur_pos]; do { y = randint(cur_height-2); x = randint(cur_width-2); } while ((cave[y][x].fval >= MIN_CLOSED_SPACE) || (cave[y][x].cptr != 0) || (cave[y][x].tptr != 0) || (distance(y,x,char_row, char_col) <= MAX_SIGHT)); mon_ptr->fy = y; mon_ptr->fx = x; mon_ptr->mptr = randint(WIN_MON_TOT) - 1 + m_level[MAX_MONS_LEVEL]; if (c_list[mon_ptr->mptr].cdefense & CD_MAX_HP) mon_ptr->hp = max_hp(c_list[mon_ptr->mptr].hd); else mon_ptr->hp = pdamroll(c_list[mon_ptr->mptr].hd); /* the c_list speed value is 10 greater, so that it can be a int8u */ mon_ptr->cspeed = c_list[mon_ptr->mptr].speed - 10 + py.flags.speed; mon_ptr->stunned = 0; mon_ptr->cdis = distance(char_row, char_col,y,x); cave[y][x].cptr = cur_pos; mon_ptr->csleep = 0; } } /* Return a monster suitable to be placed at a given level. This makes high level monsters (up to the given level) slightly more common than low level monsters at any given level. -CJS- */ int get_mons_num (level) int level; { register int i, j, num; if (level == 0) i = randint (m_level[0]) - 1; else { if (level > MAX_MONS_LEVEL) level = MAX_MONS_LEVEL; if (randint (MON_NASTY) == 1) { i = randnor (0, 4); level = level + abs(i) + 1; if (level > MAX_MONS_LEVEL) level = MAX_MONS_LEVEL; } else { /* This code has been added to make it slightly more likely to get the higher level monsters. Originally a uniform distribution over all monsters of level less than or equal to the dungeon level. This distribution makes a level n monster occur approx 2/n% of the time on level n, and 1/n*n% are 1st level. */ num = m_level[level] - m_level[0]; i = randint (num) - 1; j = randint (num) - 1; if (j > i) i = j; level = c_list[i + m_level[0]].level; } i = randint(m_level[level]-m_level[level-1]) - 1 + m_level[level-1]; } return i; } /* Allocates a random monster -RAK- */ void alloc_monster(num, dis, slp) int num, dis; int slp; { register int y, x, i; int l; for (i = 0; i < num; i++) { do { y = randint(cur_height-2); x = randint(cur_width-2); } while (cave[y][x].fval >= MIN_CLOSED_SPACE || (cave[y][x].cptr != 0) || (distance(y, x, char_row, char_col) <= dis)); l = get_mons_num (dun_level); /* Dragons are always created sleeping here, so as to give the player a sporting chance. */ if (c_list[l].cchar == 'd' || c_list[l].cchar == 'D') slp = TRUE; /* Place_monster() should always return TRUE here. It does not matter if it fails though. */ (void) place_monster(y, x, l, slp); } } /* Places creature adjacent to given location -RAK- */ int summon_monster(y, x, slp) int *y, *x; int slp; { register int i, j, k; int l, summon; register cave_type *cave_ptr; i = 0; summon = FALSE; l = get_mons_num (dun_level + MON_SUMMON_ADJ); do { j = *y - 2 + randint(3); k = *x - 2 + randint(3); if (in_bounds(j, k)) { cave_ptr = &cave[j][k]; if (cave_ptr->fval <= MAX_OPEN_SPACE && (cave_ptr->cptr == 0)) { /* Place_monster() should always return TRUE here. */ if (!place_monster(j, k, l, slp)) return FALSE; summon = TRUE; i = 9; *y = j; *x = k; } } i++; } while (i <= 9); return(summon); } /* Places undead adjacent to given location -RAK- */ int summon_undead(y, x) int *y, *x; { register int i, j, k; int l, m, ctr, summon; register cave_type *cave_ptr; i = 0; summon = FALSE; l = m_level[MAX_MONS_LEVEL]; do { m = randint(l) - 1; ctr = 0; do { if (c_list[m].cdefense & CD_UNDEAD) { ctr = 20; l = 0; } else { m++; if (m > l) ctr = 20; else ctr++; } } while (ctr <= 19); } while(l != 0); do { j = *y - 2 + randint(3); k = *x - 2 + randint(3); if (in_bounds(j, k)) { cave_ptr = &cave[j][k]; if (cave_ptr->fval <= MAX_OPEN_SPACE && (cave_ptr->cptr == 0)) { /* Place_monster() should always return TRUE here. */ if (! place_monster(j, k, m, FALSE)) return FALSE; summon = TRUE; i = 9; *y = j; *x = k; } } i++; } while(i <= 9); return(summon); } /* If too many objects on floor level, delete some of them-RAK- */ static void compact_objects() { register int i, j; int ctr, cur_dis, chance; register cave_type *cave_ptr; msg_print("Compacting objects..."); ctr = 0; cur_dis = 66; do { for (i = 0; i < cur_height; i++) for (j = 0; j < cur_width; j++) { cave_ptr = &cave[i][j]; if ((cave_ptr->tptr != 0) && (distance(i, j, char_row, char_col) > cur_dis)) { switch(t_list[cave_ptr->tptr].tval) { case TV_VIS_TRAP: chance = 15; break; case TV_INVIS_TRAP: case TV_RUBBLE: case TV_OPEN_DOOR: case TV_CLOSED_DOOR: chance = 5; break; case TV_UP_STAIR: case TV_DOWN_STAIR: case TV_STORE_DOOR: /* stairs, don't delete them */ /* shop doors, don't delete them */ chance = 0; break; case TV_SECRET_DOOR: /* secret doors */ chance = 3; break; default: chance = 10; } if (randint (100) <= chance) { (void) delete_object(i, j); ctr++; } } } if (ctr == 0) cur_dis -= 6; } while (ctr <= 0); if (cur_dis < 66) prt_map(); } /* Gives pointer to next free space -RAK- */ int popt() { if (tcptr == MAX_TALLOC) compact_objects(); return (tcptr++); } /* Pushs a record back onto free space list -RAK- */ /* Delete_object() should always be called instead, unless the object in question is not in the dungeon, e.g. in store1.c and files.c */ void pusht(x) register int8u x; { register int i, j; if (x != tcptr - 1) { t_list[x] = t_list[tcptr - 1]; /* must change the tptr in the cave of the object just moved */ for (i = 0; i < cur_height; i++) for (j = 0; j < cur_width; j++) if (cave[i][j].tptr == tcptr - 1) cave[i][j].tptr = x; } tcptr--; invcopy(&t_list[tcptr], OBJ_NOTHING); } /* Boolean : is object enchanted -RAK- */ int magik(chance) int chance; { if (randint(100) <= chance) return(TRUE); else return(FALSE); } /* Enchant a bonus based on degree desired -RAK- */ int m_bonus(base, max_std, level) int base, max_std, level; { register int x, stand_dev, tmp; stand_dev = (OBJ_STD_ADJ * level / 100) + OBJ_STD_MIN; /* Check for level > max_std since that may have generated an overflow. */ if (stand_dev > max_std || level > max_std) stand_dev = max_std; /* abs may be a macro, don't call it with randnor as a parameter */ tmp = randnor(0, stand_dev); x = (abs(tmp) / 10) + base; if (x < base) return(base); else return(x); } moria-5.6.debian.1/source/prayer.c0000644000175000017500000001256011074756544015152 0ustar pjbpjb/* source/prayer.c: code for priest spells Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" /* Pray like HELL. -RAK- */ void pray() { int i, j, item_val, dir; int choice, chance, result; register spell_type *s_ptr; register struct misc *m_ptr; register struct flags *f_ptr; register inven_type *i_ptr; #ifdef ATARIST_MWC int32u holder; #endif free_turn_flag = TRUE; if (py.flags.blind > 0) msg_print("You can't see to read your prayer!"); else if (no_light()) msg_print("You have no light to read by."); else if (py.flags.confused > 0) msg_print("You are too confused."); else if (class[py.misc.pclass].spell != PRIEST) msg_print("Pray hard enough and your prayers may be answered."); else if (inven_ctr == 0) msg_print ("But you are not carrying anything!"); else if (!find_range(TV_PRAYER_BOOK, TV_NEVER, &i, &j)) msg_print ("You are not carrying any Holy Books!"); else if (get_item(&item_val, "Use which Holy Book?", i, j, CNIL, CNIL)) { result = cast_spell("Recite which prayer?", item_val, &choice, &chance); if (result < 0) msg_print("You don't know any prayers in that book."); else if (result > 0) { s_ptr = &magic_spell[py.misc.pclass-1][choice]; free_turn_flag = FALSE; if (randint(100) < chance) msg_print("You lost your concentration!"); else { /* Prayers. */ switch(choice+1) { case 1: (void) detect_evil(); break; case 2: (void) hp_player(damroll(3, 3)); break; case 3: bless(randint(12)+12); break; case 4: (void) remove_fear(); break; case 5: (void) light_area(char_row, char_col); break; case 6: (void) detect_trap(); break; case 7: (void) detect_sdoor(); break; case 8: (void) slow_poison(); break; case 9: if (get_dir(CNIL, &dir)) (void) confuse_monster(dir, char_row, char_col); break; case 10: teleport((int)(py.misc.lev*3)); break; case 11: (void) hp_player(damroll(4, 4)); break; case 12: bless(randint(24)+24); break; case 13: (void) sleep_monsters1(char_row, char_col); break; case 14: create_food(); break; case 15: for (i = 0; i < INVEN_ARRAY_SIZE; i++) { i_ptr = &inventory[i]; /* only clear flag for items that are wielded or worn */ if (i_ptr->tval >= TV_MIN_WEAR && i_ptr->tval <= TV_MAX_WEAR) #ifdef ATARIST_MWC i_ptr->flags &= ~(holder = TR_CURSED); #else i_ptr->flags &= ~TR_CURSED; #endif } break; case 16: f_ptr = &py.flags; f_ptr->resist_heat += randint(10) + 10; f_ptr->resist_cold += randint(10) + 10; break; case 17: (void) cure_poison(); break; case 18: if (get_dir(CNIL, &dir)) fire_ball(GF_HOLY_ORB, dir, char_row, char_col, (int)(damroll(3, 6)+py.misc.lev), "Black Sphere"); break; case 19: (void) hp_player(damroll(8, 4)); break; case 20: detect_inv2(randint(24)+24); break; case 21: (void) protect_evil(); break; case 22: earthquake(); break; case 23: map_area(); break; case 24: (void) hp_player(damroll(16, 4)); break; case 25: (void) turn_undead(); break; case 26: bless(randint(48)+48); break; case 27: (void) dispel_creature(CD_UNDEAD, (int)(3*py.misc.lev)); break; case 28: (void) hp_player(200); break; case 29: (void) dispel_creature(CD_EVIL, (int)(3*py.misc.lev)); break; case 30: warding_glyph(); break; case 31: (void) remove_fear(); (void) cure_poison(); (void) hp_player(1000); for (i=A_STR; i<=A_CHR; i++) (void) res_stat(i); (void) dispel_creature(CD_EVIL, (int)(4*py.misc.lev)); (void) turn_undead(); if (py.flags.invuln < 3) py.flags.invuln = 3; else py.flags.invuln++; break; default: break; } /* End of prayers. */ if (!free_turn_flag) { m_ptr = &py.misc; if ((spell_worked & (1L << choice)) == 0) { m_ptr->exp += s_ptr->sexp << 2; prt_experience(); spell_worked |= (1L << choice); } } } m_ptr = &py.misc; if (!free_turn_flag) { if (s_ptr->smana > m_ptr->cmana) { msg_print("You faint from fatigue!"); py.flags.paralysis = randint((int)(5 * (s_ptr->smana-m_ptr->cmana))); m_ptr->cmana = 0; m_ptr->cmana_frac = 0; if (randint(3) == 1) { msg_print("You have damaged your health!"); (void) dec_stat (A_CON); } } else m_ptr->cmana -= s_ptr->smana; prt_cmana(); } } } } moria-5.6.debian.1/source/sets.c0000644000175000017500000001406611074756544014631 0ustar pjbpjb/* source/sets.c: code to emulate the original Pascal sets Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include "config.h" #include "constant.h" #include "types.h" int set_room(element) register int element; { if ((element == DARK_FLOOR) || (element == LIGHT_FLOOR)) return(TRUE); return(FALSE); } int set_corr(element) register int element; { if (element == CORR_FLOOR || element == BLOCKED_FLOOR) return(TRUE); return(FALSE); } int set_floor(element) int element; { if (element <= MAX_CAVE_FLOOR) return(TRUE); else return(FALSE); } int set_corrodes(item) inven_type *item; { switch(item->tval) { case TV_SWORD: case TV_HELM: case TV_SHIELD: case TV_HARD_ARMOR: case TV_WAND: return (TRUE); } return(FALSE); } int set_flammable(item) inven_type *item; { switch(item->tval) { case TV_ARROW: case TV_BOW: case TV_HAFTED: case TV_POLEARM: case TV_BOOTS: case TV_GLOVES: case TV_CLOAK: case TV_SOFT_ARMOR: /* Items of (RF) should not be destroyed. */ if (item->flags & TR_RES_FIRE) return FALSE; else return TRUE; case TV_STAFF: case TV_SCROLL1: case TV_SCROLL2: return TRUE; } return(FALSE); } int set_frost_destroy(item) inven_type *item; { if ((item->tval == TV_POTION1) || (item->tval == TV_POTION2) || (item->tval == TV_FLASK)) return(TRUE); return(FALSE); } int set_acid_affect(item) inven_type *item; { switch(item->tval) { case TV_MISC: case TV_CHEST: return TRUE; case TV_BOLT: case TV_ARROW: case TV_BOW: case TV_HAFTED: case TV_POLEARM: case TV_BOOTS: case TV_GLOVES: case TV_CLOAK: case TV_SOFT_ARMOR: if (item->flags & TR_RES_ACID) return (FALSE); else return (TRUE); } return(FALSE); } int set_lightning_destroy(item) inven_type *item; { if ((item->tval == TV_RING) || (item->tval == TV_WAND) || (item->tval == TV_SPIKE)) return(TRUE); else return(FALSE); } /*ARGSUSED*/ /* to shut up lint about unused argument */ #ifdef __TURBOC__ #pragma argused #endif int set_null(item) inven_type *item; #if defined(MAC) && !defined(THINK_C) #pragma unused(item) #endif { return(FALSE); } int set_acid_destroy(item) inven_type *item; { switch(item->tval) { case TV_ARROW: case TV_BOW: case TV_HAFTED: case TV_POLEARM: case TV_BOOTS: case TV_GLOVES: case TV_CLOAK: case TV_HELM: case TV_SHIELD: case TV_HARD_ARMOR: case TV_SOFT_ARMOR: if (item->flags & TR_RES_ACID) return FALSE; else return TRUE; case TV_STAFF: case TV_SCROLL1: case TV_SCROLL2: case TV_FOOD: case TV_OPEN_DOOR: case TV_CLOSED_DOOR: return(TRUE); } return(FALSE); } int set_fire_destroy(item) inven_type *item; { switch(item->tval) { case TV_ARROW: case TV_BOW: case TV_HAFTED: case TV_POLEARM: case TV_BOOTS: case TV_GLOVES: case TV_CLOAK: case TV_SOFT_ARMOR: if (item->flags & TR_RES_FIRE) return FALSE; else return TRUE; case TV_STAFF: case TV_SCROLL1: case TV_SCROLL2: case TV_POTION1: case TV_POTION2: case TV_FLASK: case TV_FOOD: case TV_OPEN_DOOR: case TV_CLOSED_DOOR: return(TRUE); } return(FALSE); } int set_large(item) /* Items too large to fit in chests -DJG- */ treasure_type *item; /* Use treasure_type since item not yet created */ { switch(item->tval) { case TV_CHEST: case TV_BOW: case TV_POLEARM: case TV_HARD_ARMOR: case TV_SOFT_ARMOR: case TV_STAFF: return TRUE; case TV_HAFTED: case TV_SWORD: case TV_DIGGING: if (item->weight > 150) return TRUE; else return FALSE; } return FALSE; } int general_store(element) int element; { switch(element) { case TV_DIGGING: case TV_BOOTS: case TV_CLOAK: case TV_FOOD: case TV_FLASK: case TV_LIGHT: case TV_SPIKE: return(TRUE); } return(FALSE); } int armory(element) int element; { switch(element) { case TV_BOOTS: case TV_GLOVES: case TV_HELM: case TV_SHIELD: case TV_HARD_ARMOR: case TV_SOFT_ARMOR: return(TRUE); } return(FALSE); } int weaponsmith(element) int element; { switch(element) { case TV_SLING_AMMO: case TV_BOLT: case TV_ARROW: case TV_BOW: case TV_HAFTED: case TV_POLEARM: case TV_SWORD: return(TRUE); } return(FALSE); } int temple(element) int element; { switch(element) { case TV_HAFTED: case TV_SCROLL1: case TV_SCROLL2: case TV_POTION1: case TV_POTION2: case TV_PRAYER_BOOK: return(TRUE); } return(FALSE); } int alchemist(element) int element; { switch(element) { case TV_SCROLL1: case TV_SCROLL2: case TV_POTION1: case TV_POTION2: return(TRUE); } return(FALSE); } int magic_shop(element) int element; { switch(element) { case TV_AMULET: case TV_RING: case TV_STAFF: case TV_WAND: case TV_SCROLL1: case TV_SCROLL2: case TV_POTION1: case TV_POTION2: case TV_MAGIC_BOOK: return(TRUE); } return(FALSE); } #ifdef MAC /* The last time tried, MPW failed to handle the initialized array of function pointers properly. hence, this hack. */ int store_buy(storeno, element) int storeno; int element; { switch (storeno) { case 0: return(general_store(element)); case 1: return(armory(element)); case 2: return(weaponsmith(element)); case 3: return(temple(element)); case 4: return(alchemist(element)); case 5: return(magic_shop(element)); } return(FALSE); } #endif moria-5.6.debian.1/source/magic.c0000644000175000017500000001311511074756544014725 0ustar pjbpjb/* source/magic.c: code for mage spells Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" /* Throw a magic spell -RAK- */ void cast() { int i, j, item_val, dir; int choice, chance, result; register struct flags *f_ptr; register struct misc *p_ptr; register inven_type *i_ptr; register spell_type *m_ptr; #ifdef ATARIST_MWC int32u holder; #endif free_turn_flag = TRUE; if (py.flags.blind > 0) msg_print("You can't see to read your spell book!"); else if (no_light()) msg_print("You have no light to read by."); else if (py.flags.confused > 0) msg_print("You are too confused."); else if (class[py.misc.pclass].spell != MAGE) msg_print("You can't cast spells!"); else if (!find_range(TV_MAGIC_BOOK, TV_NEVER, &i, &j)) msg_print("But you are not carrying any spell-books!"); else if (get_item(&item_val, "Use which spell-book?", i, j, CNIL, CNIL)) { result = cast_spell("Cast which spell?", item_val, &choice, &chance); if (result < 0) msg_print("You don't know any spells in that book."); else if (result > 0) { m_ptr = &magic_spell[py.misc.pclass-1][choice]; free_turn_flag = FALSE; if (randint(100) < chance) msg_print("You failed to get the spell off!"); else { /* Spells. */ switch(choice+1) { case 1: if (get_dir(CNIL, &dir)) fire_bolt(GF_MAGIC_MISSILE, dir, char_row, char_col, damroll(2, 6), spell_names[0]); break; case 2: (void) detect_monsters(); break; case 3: teleport(10); break; case 4: (void) light_area(char_row, char_col); break; case 5: (void) hp_player(damroll(4, 4)); break; case 6: (void) detect_sdoor(); (void) detect_trap(); break; case 7: if (get_dir(CNIL, &dir)) fire_ball(GF_POISON_GAS, dir, char_row, char_col, 12, spell_names[6]); break; case 8: if (get_dir(CNIL, &dir)) (void) confuse_monster(dir, char_row, char_col); break; case 9: if (get_dir(CNIL, &dir)) fire_bolt(GF_LIGHTNING, dir, char_row, char_col, damroll(4, 8), spell_names[8]); break; case 10: (void) td_destroy(); break; case 11: if (get_dir(CNIL, &dir)) (void) sleep_monster(dir, char_row, char_col); break; case 12: (void) cure_poison(); break; case 13: teleport((int)(py.misc.lev*5)); break; case 14: for (i = 22; i < INVEN_ARRAY_SIZE; i++) { i_ptr = &inventory[i]; #ifdef ATARIST_MWC i_ptr->flags = (i_ptr->flags & ~(holder = TR_CURSED)); #else i_ptr->flags = (i_ptr->flags & ~TR_CURSED); #endif } break; case 15: if (get_dir(CNIL, &dir)) fire_bolt(GF_FROST, dir, char_row, char_col, damroll(6, 8), spell_names[14]); break; case 16: if (get_dir(CNIL, &dir)) (void) wall_to_mud(dir, char_row, char_col); break; case 17: create_food(); break; case 18: (void) recharge(20); break; case 19: (void) sleep_monsters1(char_row, char_col); break; case 20: if (get_dir(CNIL, &dir)) (void) poly_monster(dir, char_row, char_col); break; case 21: (void) ident_spell(); break; case 22: (void) sleep_monsters2(); break; case 23: if (get_dir(CNIL, &dir)) fire_bolt(GF_FIRE, dir, char_row, char_col, damroll(9, 8), spell_names[22]); break; case 24: if (get_dir(CNIL, &dir)) (void)speed_monster(dir, char_row, char_col, -1); break; case 25: if (get_dir(CNIL, &dir)) fire_ball(GF_FROST, dir, char_row, char_col, 48, spell_names[24]); break; case 26: (void) recharge(60); break; case 27: if (get_dir(CNIL, &dir)) (void) teleport_monster(dir, char_row, char_col); break; case 28: f_ptr = &py.flags; f_ptr->fast += randint(20) + py.misc.lev; break; case 29: if (get_dir(CNIL, &dir)) fire_ball(GF_FIRE, dir, char_row, char_col, 72, spell_names[28]); break; case 30: destroy_area(char_row, char_col); break; case 31: (void) genocide(); break; default: break; } /* End of spells. */ if (!free_turn_flag) { p_ptr = &py.misc; if ((spell_worked & (1L << choice)) == 0) { p_ptr->exp += m_ptr->sexp << 2; spell_worked |= (1L << choice); prt_experience(); } } } p_ptr = &py.misc; if (!free_turn_flag) { if (m_ptr->smana > p_ptr->cmana) { msg_print("You faint from the effort!"); py.flags.paralysis = randint((int)(5*(m_ptr->smana-p_ptr->cmana))); p_ptr->cmana = 0; p_ptr->cmana_frac = 0; if (randint(3) == 1) { msg_print("You have damaged your health!"); (void) dec_stat (A_CON); } } else p_ptr->cmana -= m_ptr->smana; prt_cmana(); } } } } moria-5.6.debian.1/source/variable.c0000644000175000017500000000773511074756544015445 0ustar pjbpjb/* source/variable.c: Global variables */ char *copyright[17] = { "Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, ", " David J. Grabiner", "", "This file is part of Umoria.", "", "Umoria is free software; you can redistribute it and/or modify ", "it under the terms of the GNU General Public License as published by", "the Free Software Foundation, either version 3 of the License, or", "(at your option) any later version.", "", "Umoria is distributed in the hope that it will be useful,", "but WITHOUT ANY WARRANTY; without even the implied warranty of ", "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", "GNU General Public License for more details.", "", "You should have received a copy of the GNU General Public License ", "along with Umoria. If not, see ." }; #include #include "config.h" #include "constant.h" #include "types.h" /* Save the store's last increment value. */ int16 last_store_inc; /* a horrible hack: needed because compact_monster() can be called from creatures() via summon_monster() and place_monster() */ int hack_monptr = -1; int weapon_heavy = FALSE; int pack_heavy = FALSE; vtype died_from; int32 birth_date; vtype savefile; /* The savefile to use. */ int16 total_winner = FALSE; int32 max_score = 0; int character_generated = 0; /* don't save score until char gen finished */ int character_saved = 0; /* prevents save on kill after save_char() */ FILE *highscore_fp; /* File pointer to high score file */ int32u randes_seed; /* for restarting randes_state */ int32u town_seed; /* for restarting town_seed */ int16 cur_height,cur_width; /* Cur dungeon size */ int16 dun_level = 0; /* Cur dungeon level */ int16 missile_ctr = 0; /* Counter for missiles */ int msg_flag; /* Set with first msg */ vtype old_msg[MAX_SAVE_MSG]; /* Last message */ int16 last_msg = 0; /* Where last is held */ int death = FALSE; /* True if died */ int find_flag; /* Used in MORIA for .(dir) */ int free_turn_flag; /* Used in MORIA, do not move creatures */ int command_count; /* Gives repetition of commands. -CJS- */ int default_dir = FALSE; /* Use last direction for repeated command */ int32 turn = -1; /* Cur turn of game */ int wizard = FALSE; /* Wizard flag */ int to_be_wizard = FALSE; /* used during startup, when -w option used */ int16 panic_save = FALSE; /* this is true if playing from a panic save */ int16 noscore = FALSE; /* Don't log the game. -CJS- */ int rogue_like_commands; /* set in config.h/main.c */ /* options set via the '=' command */ int find_cut = TRUE; int find_examine = TRUE; int find_bound = FALSE; int find_prself = FALSE; int prompt_carry_flag = FALSE; int show_weight_flag = FALSE; int highlight_seams = FALSE; int find_ignore_doors = FALSE; int sound_beep_flag = TRUE; int display_counts = TRUE; char doing_inven = FALSE; /* Track inventory commands. -CJS- */ int screen_change = FALSE; /* Track screen updates for inven_commands. */ char last_command = ' '; /* Memory of previous command. */ /* these used to be in dungeon.c */ int new_level_flag; /* Next level when true */ int teleport_flag; /* Handle teleport traps */ int player_light; /* Player carrying light */ int eof_flag = FALSE; /* Used to signal EOF/HANGUP condition */ int light_flag = FALSE; /* Track if temporary light about player. */ int wait_for_more = FALSE; /* used when ^C hit during -more- prompt */ int closing_flag = FALSE; /* Used for closing */ /* Following are calculated from max dungeon sizes */ int16 max_panel_rows,max_panel_cols; int panel_row,panel_col; int panel_row_min,panel_row_max; int panel_col_min,panel_col_max; int panel_col_prt,panel_row_prt; #ifdef MAC cave_type (*cave)[MAX_WIDTH]; #else cave_type cave[MAX_HEIGHT][MAX_WIDTH]; #endif #ifdef MAC recall_type *c_recall; #else recall_type c_recall[MAX_CREATURES]; /* Monster memories */ #endif /* See atarist/st-stuff.c */ #if defined(atarist) && defined(__GNUC__) char extended_file_name[80]; #endif moria-5.6.debian.1/source/files.c0000644000175000017500000003731211074756544014754 0ustar pjbpjb/* source/files.c: misc code to access files used by Moria Copyright (c) 1989-94 James E. Wilson, Robert A. Koeneke This software may be copied and distributed for educational, research, and not for profit purposes provided that this copyright and statement are included in all such copies. */ #include #if 0 /* moved to externs.h to avoid VMS 'psect' problem */ #include #endif #ifdef __TURBOC__ #include #include #endif /* __TURBOC__ */ #include "config.h" #include "constant.h" #include "types.h" #if defined(GEMDOS) && (__STDC__ == 0) && !defined(ATARIST_TC) #include char *strcat(); #endif #ifdef VMS #include #include #else #ifdef USG #ifndef ATARIST_MWC #include #ifndef ATARIST_TC #include #endif #endif #else #include #include #endif #if defined(ultrix) || defined(USG) void exit(); #endif #endif /* This must be included after fcntl.h, which has a prototype for `open' on some systems. Otherwise, the `open' prototype conflicts with the `topen' declaration. */ #include "externs.h" #ifdef ATARIST_TC /* Include this to get prototypes for standard library functions. */ #include #endif #ifdef MAC #include "ScrnMgr.h" #define GNRL_ALRT 1024 #endif /* * init_scorefile * Open the score file while we still have the setuid privileges. Later * when the score is being written out, you must be sure to flock the file * so we don't have multiple people trying to write to it at the same time. * Craig Norborg (doc) Mon Aug 10 16:41:59 EST 1987 */ void init_scorefile() { #ifdef MAC appldirectory (); #endif #if defined(atarist) || defined(ATARI_ST) || defined(MAC) highscore_fp = fopen(MORIA_TOP, "rb+"); #else highscore_fp = fopen(MORIA_TOP, "r+"); #endif if (highscore_fp == NULL) { #ifdef MAC highscore_fp = fopen (MORIA_TOP, "wb"); /* Create it if not there. */ if (highscore_fp == NULL) { ParamText ("\pCan't create score file!", NULL, NULL, NULL); DoScreenALRT (GNRL_ALRT, akStop, fixHalf, fixThird); ExitToShell (); } setfileinfo (MORIA_TOP, currentdirectory (), SCORE_FTYPE); #else (void) fprintf (stderr, "Can't open score file \"%s\"\n", MORIA_TOP); exit(1); #endif } #if defined(MSDOS) || defined(VMS) || defined(MAC) || defined(APOLLO) /* can't leave it open, since this causes problems on networked PCs and VMS, we DO want to check to make sure we can open the file, though */ fclose (highscore_fp); #endif #ifdef MAC restoredirectory (); #endif } #ifndef MAC /* Attempt to open the intro file -RAK- */ /* This routine also checks the hours file vs. what time it is -Doc */ void read_times() { vtype in_line; register int i; FILE *file1; #ifdef MORIA_HOU /* Attempt to read hours.dat. If it does not exist, */ /* inform the user so he can tell the wizard about it */ if ((file1 = fopen(MORIA_HOU, "r")) != NULL) { while (fgets(in_line, 80, file1) != CNIL) if (strlen(in_line) > 3) { if (!strncmp(in_line, "SUN:", 4)) (void) strcpy(days[0], in_line); else if (!strncmp(in_line, "MON:", 4)) (void) strcpy(days[1], in_line); else if (!strncmp(in_line, "TUE:", 4)) (void) strcpy(days[2], in_line); else if (!strncmp(in_line, "WED:", 4)) (void) strcpy(days[3], in_line); else if (!strncmp(in_line, "THU:", 4)) (void) strcpy(days[4], in_line); else if (!strncmp(in_line, "FRI:", 4)) (void) strcpy(days[5], in_line); else if (!strncmp(in_line, "SAT:", 4)) (void) strcpy(days[6], in_line); } (void) fclose(file1); } else { restore_term(); (void) fprintf(stderr, "There is no hours file \"%s\".\n", MORIA_HOU); (void) fprintf(stderr, "Please inform the wizard, %s, so he ", WIZARD); (void) fprintf(stderr, "can correct this!\n"); exit(1); } /* Check the hours, if closed then exit. */ if (!check_time()) { if ((file1 = fopen(MORIA_HOU, "r")) != NULL) { clear_screen(); #ifdef VMS restore_screen(); #endif for (i = 0; fgets(in_line, 80, file1) != CNIL; i++) put_buffer(in_line, i, 0); pause_line (23); (void) fclose(file1); } exit_game(); } #endif /* Print the introduction message, news, etc. */ if ((file1 = fopen(MORIA_MOR, "r")) != NULL) { clear_screen(); #ifdef VMS restore_screen(); #endif for (i = 0; fgets(in_line, 80, file1) != CNIL; i++) put_buffer(in_line, i, 0); pause_line(23); (void) fclose(file1); } } #endif /* File perusal. -CJS- primitive, but portable */ void helpfile(filename) char *filename; #ifdef MAC { mac_helpfile(filename, TRUE); } #else { bigvtype tmp_str; FILE *file; char input; int i; file = fopen(filename, "r"); if (file == NULL) { (void) sprintf (tmp_str, "Can not find help file \"%s\".\n", filename); prt (tmp_str, 0, 0); return; } save_screen(); while (!feof(file)) { clear_screen(); for (i = 0; i < 23; i++) if (fgets (tmp_str, BIGVTYPESIZ-1, file) != CNIL) put_buffer (tmp_str, i, 0); prt("[Press any key to continue.]", 23, 23); input = inkey(); if (input == ESCAPE) break; } (void) fclose(file); restore_screen(); } #endif /* Prints a list of random objects to a file. Note that -RAK- */ /* the objects produced is a sampling of objects which */ /* be expected to appear on that level. */ void print_objects() { register int i; int nobj, j, level, small; vtype filename1; bigvtype tmp_str; register FILE *file1; register inven_type *i_ptr; #ifdef MAC short vrefnum; #endif #ifdef ATARIST_MWC int32u holder; #endif prt("Produce objects on what level?: ", 0, 0); level = 0; if (!get_string(tmp_str, 0, 32, 10)) return; level = atoi(tmp_str); prt("Produce how many objects?: ", 0, 0); nobj = 0; if (!get_string(tmp_str, 0, 27, 10)) return; nobj = atoi(tmp_str); small = get_check("Small objects only?"); if ((nobj > 0) && (level > -1) && (level < 1201)) { if (nobj > 10000) nobj = 10000; #ifdef MAC (void) strcpy(filename1, "Objects"); if (doputfile("Save objects in:", filename1, &vrefnum)) #else prt("File name: ", 0, 0); if (get_string(filename1, 0, 11, 64)) #endif { if (strlen(filename1) == 0) return; #ifdef MAC changedirectory(vrefnum); #endif if ((file1 = fopen(filename1, "w")) != NULL) { #ifdef MAC macbeginwait (); #endif (void) sprintf(tmp_str, "%d", nobj); prt(strcat(tmp_str, " random objects being produced..."), 0, 0); put_qio(); (void) fprintf(file1, "*** Random Object Sampling:\n"); (void) fprintf(file1, "*** %d objects\n", nobj); (void) fprintf(file1, "*** For Level %d\n", level); (void) fprintf(file1, "\n"); (void) fprintf(file1, "\n"); j = popt(); for (i = 0; i < nobj; i++) { invcopy(&t_list[j], sorted_objects[get_obj_num(level,small)]); magic_treasure(j, level); i_ptr = &t_list[j]; store_bought(i_ptr); #ifdef ATARIST_MWC if (i_ptr->flags & (holder = TR_CURSED)) #else if (i_ptr->flags & TR_CURSED) #endif add_inscribe(i_ptr, ID_DAMD); objdes(tmp_str, i_ptr, TRUE); (void) fprintf(file1, "%d %s\n", i_ptr->level, tmp_str); } pusht((int8u)j); (void) fclose(file1); #ifdef MAC setfileinfo(filename1, vrefnum, INFO_FTYPE); macendwait (); #endif prt("Completed.", 0, 0); } else prt("File could not be opened.", 0, 0); #ifdef MAC restoredirectory(); #endif } } else prt ("Parameters no good.", 0, 0); } /* Print the character to a file or device -RAK- */ #ifdef MAC int file_character() #else int file_character(filename1) char *filename1; #endif { register int i; int j, xbth, xbthb, xfos, xsrh, xstl, xdis, xsave, xdev; vtype xinfra; int fd; register FILE *file1; bigvtype prt2; register struct misc *p_ptr; register inven_type *i_ptr; vtype out_val, prt1; char *p, *colon, *blank; #ifdef MAC vtype filename1; short vrefnum; #endif #ifdef MAC (void) makefilename(filename1, "Stats", TRUE); if (!doputfile("Save character description in:", filename1, &vrefnum)) return (FALSE); #endif #ifndef VMS /* VMS creates a new version of a file, so no need to check for rewrite. */ #ifdef MAC changedirectory(vrefnum); fd = open (filename1, O_WRONLY|O_CREAT|O_TRUNC); restoredirectory(); macbeginwait (); #else #if defined(GEMDOS) && (__STDC__ == 0) && !defined(ATARIST_TC) if (!access(filename1, AREAD)) { (void) sprintf(out_val, "Replace existing file %s?", filename1); if (get_check(out_val)) fd = creat(filename1, 1); } else fd = creat (filename1, 1); #else fd = open (filename1, O_WRONLY|O_CREAT|O_EXCL, 0644); if (fd < 0 && errno == EEXIST) { (void) sprintf(out_val, "Replace existing file %s?", filename1); if (get_check(out_val)) fd = open(filename1, O_WRONLY, 0644); } #endif #endif if (fd >= 0) { /* on some non-unix machines, fdopen() is not reliable, hence must call close() and then fopen() */ (void) close(fd); file1 = fopen(filename1, "w"); } else file1 = NULL; #else /* VMS */ fd = -1; file1 = fopen (filename1, "w"); #endif if (file1 != NULL) { prt("Writing character sheet...", 0, 0); put_qio(); colon = ":"; blank = " "; #ifdef MAC (void) fprintf(file1, "\n\n"); #else (void) fprintf(file1, "%c\n\n", CTRL('L')); #endif (void) fprintf(file1, " Name%9s %-23s", colon, py.misc.name); (void) fprintf(file1, " Age%11s %6d", colon, (int)py.misc.age); cnv_stat(py.stats.use_stat[A_STR], prt1); (void) fprintf(file1, " STR : %s\n", prt1); (void) fprintf(file1, " Race%9s %-23s", colon, race[py.misc.prace].trace); (void) fprintf(file1, " Height%8s %6d", colon, (int)py.misc.ht); cnv_stat(py.stats.use_stat[A_INT], prt1); (void) fprintf(file1, " INT : %s\n", prt1); (void) fprintf(file1, " Sex%10s %-23s", colon, (py.misc.male ? "Male" : "Female")); (void) fprintf(file1, " Weight%8s %6d", colon, (int)py.misc.wt); cnv_stat(py.stats.use_stat[A_WIS], prt1); (void) fprintf(file1, " WIS : %s\n", prt1); (void) fprintf(file1, " Class%8s %-23s", colon, class[py.misc.pclass].title); (void) fprintf(file1, " Social Class : %6d", py.misc.sc); cnv_stat(py.stats.use_stat[A_DEX], prt1); (void) fprintf(file1, " DEX : %s\n", prt1); (void) fprintf(file1, " Title%8s %-23s", colon, title_string()); (void) fprintf(file1, "%22s", blank); cnv_stat(py.stats.use_stat[A_CON], prt1); (void) fprintf(file1, " CON : %s\n", prt1); (void) fprintf(file1, "%34s", blank); (void) fprintf(file1, "%26s", blank); cnv_stat(py.stats.use_stat[A_CHR], prt1); (void) fprintf(file1, " CHR : %s\n\n", prt1); (void) fprintf(file1, " + To Hit : %6d", py.misc.dis_th); (void) fprintf(file1, "%7sLevel : %7d", blank, (int)py.misc.lev); (void) fprintf(file1, " Max Hit Points : %6d\n", py.misc.mhp); (void) fprintf(file1, " + To Damage : %6d", py.misc.dis_td); (void) fprintf(file1, "%7sExperience : %7ld", blank, py.misc.exp); (void) fprintf(file1, " Cur Hit Points : %6d\n", py.misc.chp); (void) fprintf(file1, " + To AC : %6d", py.misc.dis_tac); (void) fprintf(file1, "%7sMax Exp : %7ld", blank, py.misc.max_exp); (void) fprintf(file1, " Max Mana%8s %6d\n", colon, py.misc.mana); (void) fprintf(file1, " Total AC : %6d", py.misc.dis_ac); if (py.misc.lev >= MAX_PLAYER_LEVEL) (void) fprintf (file1, "%7sExp to Adv : *******", blank); else (void) fprintf(file1, "%7sExp to Adv : %7ld", blank, (int32)(player_exp[py.misc.lev-1] * py.misc.expfact / 100)); (void) fprintf(file1, " Cur Mana%8s %6d\n", colon, py.misc.cmana); (void) fprintf(file1, "%28sGold%8s %7ld\n\n", blank, colon, py.misc.au); p_ptr = &py.misc; xbth = p_ptr->bth + p_ptr->ptohit * BTH_PLUS_ADJ + (class_level_adj[p_ptr->pclass][CLA_BTH] * p_ptr->lev); xbthb = p_ptr->bthb + p_ptr->ptohit * BTH_PLUS_ADJ + (class_level_adj[p_ptr->pclass][CLA_BTHB] * p_ptr->lev); /* this results in a range from 0 to 29 */ xfos = 40 - p_ptr->fos; if (xfos < 0) xfos = 0; xsrh = p_ptr->srh; /* this results in a range from 0 to 9 */ xstl = p_ptr->stl + 1; xdis = p_ptr->disarm + 2 * todis_adj() + stat_adj(A_INT) + (class_level_adj[p_ptr->pclass][CLA_DISARM] * p_ptr->lev / 3); xsave = p_ptr->save + stat_adj(A_WIS) + (class_level_adj[p_ptr->pclass][CLA_SAVE] * p_ptr->lev / 3); xdev = p_ptr->save + stat_adj(A_INT) + (class_level_adj[p_ptr->pclass][CLA_DEVICE] * p_ptr->lev / 3); (void) sprintf(xinfra, "%d feet", py.flags.see_infra * 10); (void) fprintf(file1, "(Miscellaneous Abilities)\n\n"); (void) fprintf(file1, " Fighting : %-10s", likert(xbth, 12)); (void) fprintf(file1, " Stealth : %-10s", likert(xstl, 1)); (void) fprintf(file1, " Perception : %s\n", likert(xfos, 3)); (void) fprintf(file1, " Bows/Throw : %-10s", likert(xbthb, 12)); (void) fprintf(file1, " Disarming : %-10s", likert(xdis, 8)); (void) fprintf(file1, " Searching : %s\n", likert(xsrh, 6)); (void) fprintf(file1, " Saving Throw: %-10s", likert(xsave, 6)); (void) fprintf(file1, " Magic Device: %-10s", likert(xdev, 6)); (void) fprintf(file1, " Infra-Vision: %s\n\n", xinfra); /* Write out the character's history */ (void) fprintf(file1, "Character Background\n"); for (i = 0; i < 4; i++) (void) fprintf(file1, " %s\n", py.misc.history[i]); /* Write out the equipment list. */ j = 0; (void) fprintf(file1, "\n [Character's Equipment List]\n\n"); if (equip_ctr == 0) (void) fprintf(file1, " Character has no equipment in use.\n"); else for (i = INVEN_WIELD; i < INVEN_ARRAY_SIZE; i++) { i_ptr = &inventory[i]; if (i_ptr->tval != TV_NOTHING) { switch (i) { case INVEN_WIELD: p = "You are wielding"; break; case INVEN_HEAD: p = "Worn on head"; break; case INVEN_NECK: p = "Worn around neck"; break; case INVEN_BODY: p = "Worn on body"; break; case INVEN_ARM: p = "Worn on shield arm";break; case INVEN_HANDS: p = "Worn on hands"; break; case INVEN_RIGHT: p = "Right ring finger";break; case INVEN_LEFT: p = "Left ring finger";break; case INVEN_FEET: p = "Worn on feet"; break; case INVEN_OUTER: p = "Worn about body"; break; case INVEN_LIGHT: p = "Light source is"; break; case INVEN_AUX: p = "Secondary weapon"; break; default: p = "*Unknown value*"; break; } objdes(prt2, &inventory[i], TRUE); (void) fprintf(file1, " %c) %-19s: %s\n", j+'a', p, prt2); j++; } } /* Write out the character's inventory. */ #ifdef MAC (void) fprintf(file1, "\n\n"); #else (void) fprintf(file1, "%c\n\n", CTRL('L')); #endif (void) fprintf(file1, " [General Inventory List]\n\n"); if (inven_ctr == 0) (void) fprintf(file1, " Character has no objects in inventory.\n"); else { for (i = 0; i < inven_ctr; i++) { objdes(prt2, &inventory[i], TRUE); (void) fprintf(file1, "%c) %s\n", i+'a', prt2); } } #ifndef MAC (void) fprintf(file1, "%c", CTRL('L')); #endif (void) fclose(file1); #ifdef MAC setfileinfo(filename1, vrefnum, INFO_FTYPE); macendwait (); #endif prt("Completed.", 0, 0); return TRUE; } else { if (fd >= 0) (void) close (fd); (void) sprintf (out_val, "Can't open file %s:", filename1); msg_print(out_val); return FALSE; } } moria-5.6.debian.1/source/spells.c0000644000175000017500000016662711074756544015170 0ustar pjbpjb/* source/spells.c: player/creature spells, breaths, wands, scrolls, etc. code Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include #include #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #ifdef USG #ifndef ATARIST_MWC #include #endif #else #include #endif #if defined(LINT_ARGS) static void replace_spot(int, int, int); #else static void replace_spot(); #endif /* Following are spell procedure/functions -RAK- */ /* These routines are commonly used in the scroll, potion, wands, and */ /* staves routines, and are occasionally called from other areas. */ /* Now included are creature spells also. -RAK */ void monster_name (m_name, m_ptr, r_ptr) char *m_name; monster_type *m_ptr; creature_type *r_ptr; { if (!m_ptr->ml) (void) strcpy (m_name, "It"); else (void) sprintf (m_name, "The %s", r_ptr->name); } void lower_monster_name (m_name, m_ptr, r_ptr) char *m_name; monster_type *m_ptr; creature_type *r_ptr; { if (!m_ptr->ml) (void) strcpy (m_name, "it"); else (void) sprintf (m_name, "the %s", r_ptr->name); } /* Sleep creatures adjacent to player -RAK- */ int sleep_monsters1(y, x) int y, x; { register int i, j; register cave_type *c_ptr; register monster_type *m_ptr; register creature_type *r_ptr; int sleep; vtype out_val, m_name; sleep = FALSE; for (i = y-1; i <= y+1; i++) for (j = x-1; j <= x+1; j++) { c_ptr = &cave[i][j]; if (c_ptr->cptr > 1) { m_ptr = &m_list[c_ptr->cptr]; r_ptr = &c_list[m_ptr->mptr]; monster_name (m_name, m_ptr, r_ptr); if ((randint(MAX_MONS_LEVEL) < r_ptr->level) || (CD_NO_SLEEP & r_ptr->cdefense)) { if (m_ptr->ml && (r_ptr->cdefense & CD_NO_SLEEP)) c_recall[m_ptr->mptr].r_cdefense |= CD_NO_SLEEP; (void) sprintf(out_val, "%s is unaffected.", m_name); msg_print(out_val); } else { sleep = TRUE; m_ptr->csleep = 500; (void) sprintf(out_val, "%s falls asleep.", m_name); msg_print(out_val); } } } return(sleep); } /* Detect any treasure on the current panel -RAK- */ int detect_treasure() { register int i, j, detect; register cave_type *c_ptr; detect = FALSE; for (i = panel_row_min; i <= panel_row_max; i++) for (j = panel_col_min; j <= panel_col_max; j++) { c_ptr = &cave[i][j]; if ((c_ptr->tptr != 0) && (t_list[c_ptr->tptr].tval == TV_GOLD) && !test_light(i, j)) { c_ptr->fm = TRUE; lite_spot(i, j); detect = TRUE; } } return(detect); } /* Detect all objects on the current panel -RAK- */ int detect_object() { register int i, j, detect; register cave_type *c_ptr; detect = FALSE; for (i = panel_row_min; i <= panel_row_max; i++) for (j = panel_col_min; j <= panel_col_max; j++) { c_ptr = &cave[i][j]; if ((c_ptr->tptr != 0) && (t_list[c_ptr->tptr].tval < TV_MAX_OBJECT) && !test_light(i, j)) { c_ptr->fm = TRUE; lite_spot(i, j); detect = TRUE; } } return(detect); } /* Locates and displays traps on current panel -RAK- */ int detect_trap() { register int i, j; int detect; register cave_type *c_ptr; register inven_type *t_ptr; detect = FALSE; for (i = panel_row_min; i <= panel_row_max; i++) for (j = panel_col_min; j <= panel_col_max; j++) { c_ptr = &cave[i][j]; if (c_ptr->tptr != 0) if (t_list[c_ptr->tptr].tval == TV_INVIS_TRAP) { c_ptr->fm = TRUE; change_trap(i, j); detect = TRUE; } else if (t_list[c_ptr->tptr].tval == TV_CHEST) { t_ptr = &t_list[c_ptr->tptr]; known2(t_ptr); } } return(detect); } /* Locates and displays all secret doors on current panel -RAK- */ int detect_sdoor() { register int i, j, detect; register cave_type *c_ptr; detect = FALSE; for (i = panel_row_min; i <= panel_row_max; i++) for (j = panel_col_min; j <= panel_col_max; j++) { c_ptr = &cave[i][j]; if (c_ptr->tptr != 0) /* Secret doors */ if (t_list[c_ptr->tptr].tval == TV_SECRET_DOOR) { c_ptr->fm = TRUE; change_trap(i, j); detect = TRUE; } /* Staircases */ else if (((t_list[c_ptr->tptr].tval == TV_UP_STAIR) || (t_list[c_ptr->tptr].tval == TV_DOWN_STAIR)) && !c_ptr->fm) { c_ptr->fm = TRUE; lite_spot(i, j); detect = TRUE; } } return(detect); } /* Locates and displays all invisible creatures on current panel -RAK-*/ int detect_invisible() { register int i, flag; register monster_type *m_ptr; #ifdef ATARIST_MWC int32u holder; #endif flag = FALSE; for (i = mfptr - 1; i >= MIN_MONIX; i--) { m_ptr = &m_list[i]; if (panel_contains((int)m_ptr->fy, (int)m_ptr->fx) && #ifdef ATARIST_MWC ((holder = CM_INVISIBLE) & c_list[m_ptr->mptr].cmove)) #else (CM_INVISIBLE & c_list[m_ptr->mptr].cmove)) #endif { m_ptr->ml = TRUE; /* works correctly even if hallucinating */ print((char)c_list[m_ptr->mptr].cchar, (int)m_ptr->fy, (int)m_ptr->fx); flag = TRUE; } } if (flag) { msg_print("You sense the presence of invisible creatures!"); msg_print(CNIL); /* must unlight every monster just lighted */ creatures(FALSE); } return(flag); } /* Light an area: 1. If corridor light immediate area -RAK-*/ /* 2. If room light entire room plus immediate area. */ int light_area(y, x) register int y, x; { register int i, j, light; if (py.flags.blind < 1) msg_print("You are surrounded by a white light."); light = TRUE; if (cave[y][x].lr && (dun_level > 0)) light_room(y, x); /* Must always light immediate area, because one might be standing on the edge of a room, or next to a destroyed area, etc. */ for (i = y-1; i <= y+1; i++) for (j = x-1; j <= x+1; j++) { cave[i][j].pl = TRUE; lite_spot(i, j); } return(light); } /* Darken an area, opposite of light area -RAK- */ int unlight_area(y, x) int y, x; { register int i, j; int tmp1, tmp2, unlight; int start_row, start_col, end_row, end_col; register cave_type *c_ptr; unlight = FALSE; if (cave[y][x].lr && (dun_level > 0)) { tmp1 = (SCREEN_HEIGHT/2); tmp2 = (SCREEN_WIDTH /2); start_row = (y/tmp1)*tmp1 + 1; start_col = (x/tmp2)*tmp2 + 1; end_row = start_row + tmp1 - 1; end_col = start_col + tmp2 - 1; for (i = start_row; i <= end_row; i++) { for (j = start_col; j <= end_col; j++) { c_ptr = &cave[i][j]; if (c_ptr->lr && c_ptr->fval <= MAX_CAVE_FLOOR) { c_ptr->pl = FALSE; c_ptr->fval = DARK_FLOOR; lite_spot (i, j); if (!test_light(i, j)) unlight = TRUE; } } } } else for (i = y-1; i <= y+1; i++) for (j = x-1; j <= x+1; j++) { c_ptr = &cave[i][j]; if ((c_ptr->fval == CORR_FLOOR) && c_ptr->pl) { /* pl could have been set by star-lite wand, etc */ c_ptr->pl = FALSE; unlight = TRUE; } } if (unlight && py.flags.blind <= 0) msg_print("Darkness surrounds you."); return(unlight); } /* Map the current area plus some -RAK- */ void map_area() { register cave_type *c_ptr; register int i7, i8, n, m; int i, j, k, l; i = panel_row_min - randint(10); j = panel_row_max + randint(10); k = panel_col_min - randint(20); l = panel_col_max + randint(20); for (m = i; m <= j; m++) for (n = k; n <= l; n++) if (in_bounds(m, n) && (cave[m][n].fval <= MAX_CAVE_FLOOR)) for (i7 = m-1; i7 <= m+1; i7++) for (i8 = n-1; i8 <= n+1; i8++) { c_ptr = &cave[i7][i8]; if (c_ptr->fval >= MIN_CAVE_WALL) c_ptr->pl = TRUE; else if ((c_ptr->tptr != 0) && (t_list[c_ptr->tptr].tval >= TV_MIN_VISIBLE) && (t_list[c_ptr->tptr].tval <= TV_MAX_VISIBLE)) c_ptr->fm = TRUE; } prt_map(); } /* Identify an object -RAK- */ int ident_spell() { int item_val; bigvtype out_val, tmp_str; register int ident; register inven_type *i_ptr; ident = FALSE; if (get_item(&item_val, "Item you wish identified?", 0, INVEN_ARRAY_SIZE, CNIL, CNIL)) { ident = TRUE; identify(&item_val); i_ptr = &inventory[item_val]; known2(i_ptr); objdes(tmp_str, i_ptr, TRUE); if (item_val >= INVEN_WIELD) { calc_bonuses(); (void) sprintf (out_val, "%s: %s", describe_use(item_val), tmp_str); } else (void) sprintf(out_val, "%c %s", item_val+97, tmp_str); msg_print(out_val); } return(ident); } /* Get all the monsters on the level pissed off. -RAK- */ int aggravate_monster (dis_affect) int dis_affect; { register int i, aggravate; register monster_type *m_ptr; aggravate = FALSE; for (i = mfptr - 1; i >= MIN_MONIX; i--) { m_ptr = &m_list[i]; m_ptr->csleep = 0; if ((m_ptr->cdis <= dis_affect) && (m_ptr->cspeed < 2)) { m_ptr->cspeed++; aggravate = TRUE; } } if (aggravate) msg_print ("You hear a sudden stirring in the distance!"); return(aggravate); } /* Surround the fool with traps (chuckle) -RAK- */ int trap_creation() { register int i, j, trap; register cave_type *c_ptr; trap = TRUE; for (i = char_row-1; i <= char_row+1; i++) for (j = char_col-1; j <= char_col+1; j++) { /* Don't put a trap under the player, since this can lead to strange situations, e.g. falling through a trap door while trying to rest, setting off a falling rock trap and ending up under the rock. */ if (i == char_row && j == char_col) continue; c_ptr = &cave[i][j]; if (c_ptr->fval <= MAX_CAVE_FLOOR) { if (c_ptr->tptr != 0) (void) delete_object(i, j); place_trap(i, j, randint(MAX_TRAP)-1); /* don't let player gain exp from the newly created traps */ t_list[c_ptr->tptr].p1 = 0; /* open pits are immediately visible, so call lite_spot */ lite_spot(i, j); } } return(trap); } /* Surround the player with doors. -RAK- */ int door_creation() { register int i, j, door; int k; register cave_type *c_ptr; door = FALSE; for (i = char_row-1; i <= char_row+1; i++) for (j = char_col-1; j <= char_col+1; j++) if ((i != char_row) || (j != char_col)) { c_ptr = &cave[i][j]; if (c_ptr->fval <= MAX_CAVE_FLOOR) { door = TRUE; if (c_ptr->tptr != 0) (void) delete_object(i, j); k = popt(); c_ptr->fval = BLOCKED_FLOOR; c_ptr->tptr = k; invcopy(&t_list[k], OBJ_CLOSED_DOOR); lite_spot(i, j); } } return(door); } /* Destroys any adjacent door(s)/trap(s) -RAK- */ int td_destroy() { register int i, j, destroy; register cave_type *c_ptr; destroy = FALSE; for (i = char_row-1; i <= char_row+1; i++) for (j = char_col-1; j <= char_col+1; j++) { c_ptr = &cave[i][j]; if (c_ptr->tptr != 0) { if (((t_list[c_ptr->tptr].tval >= TV_INVIS_TRAP) && (t_list[c_ptr->tptr].tval <= TV_CLOSED_DOOR) && (t_list[c_ptr->tptr].tval != TV_RUBBLE)) || (t_list[c_ptr->tptr].tval == TV_SECRET_DOOR)) { if (delete_object(i, j)) destroy = TRUE; } else if ((t_list[c_ptr->tptr].tval == TV_CHEST) && (t_list[c_ptr->tptr].flags != 0)) { /* destroy traps on chest and unlock */ t_list[c_ptr->tptr].flags &= ~(CH_TRAPPED|CH_LOCKED); t_list[c_ptr->tptr].name2 = SN_UNLOCKED; msg_print ("You have disarmed the chest."); known2(&t_list[c_ptr->tptr]); destroy = TRUE; } } } return(destroy); } /* Display all creatures on the current panel -RAK- */ int detect_monsters() { register int i, detect; register monster_type *m_ptr; #ifdef ATARIST_MWC int32u holder; #endif detect = FALSE; for (i = mfptr - 1; i >= MIN_MONIX; i--) { m_ptr = &m_list[i]; if (panel_contains((int)m_ptr->fy, (int)m_ptr->fx) && #ifdef ATARIST_MWC (((holder = CM_INVISIBLE) & c_list[m_ptr->mptr].cmove) == 0)) #else ((CM_INVISIBLE & c_list[m_ptr->mptr].cmove) == 0)) #endif { m_ptr->ml = TRUE; /* works correctly even if hallucinating */ print((char)c_list[m_ptr->mptr].cchar, (int)m_ptr->fy, (int)m_ptr->fx); detect = TRUE; } } if (detect) { msg_print("You sense the presence of monsters!"); msg_print(CNIL); /* must unlight every monster just lighted */ creatures(FALSE); } return(detect); } /* Leave a line of light in given dir, blue light can sometimes */ /* hurt creatures. -RAK- */ void light_line(dir, y, x) int dir, y, x; { register int i; register cave_type *c_ptr; register monster_type *m_ptr; register creature_type *r_ptr; int dist, flag; vtype out_val, m_name; dist = -1; flag = FALSE; do { /* put mmove at end because want to light up current spot */ dist++; c_ptr = &cave[y][x]; if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE) flag = TRUE; else { if (!c_ptr->pl && !c_ptr->tl) { /* set pl so that lite_spot will work */ c_ptr->pl = TRUE; if (c_ptr->fval == LIGHT_FLOOR) { if (panel_contains(y, x)) light_room(y, x); } else lite_spot(y, x); } /* set pl in case tl was true above */ c_ptr->pl = TRUE; if (c_ptr->cptr > 1) { m_ptr = &m_list[c_ptr->cptr]; r_ptr = &c_list[m_ptr->mptr]; /* light up and draw monster */ update_mon ((int)c_ptr->cptr); monster_name (m_name, m_ptr, r_ptr); if (CD_LIGHT & r_ptr->cdefense) { if (m_ptr->ml) c_recall[m_ptr->mptr].r_cdefense |= CD_LIGHT; i = mon_take_hit((int)c_ptr->cptr, damroll(2, 8)); if (i >= 0) { (void) sprintf(out_val, "%s shrivels away in the light!", m_name); msg_print(out_val); prt_experience(); } else { (void) sprintf(out_val, "%s cringes from the light!", m_name); msg_print (out_val); } } } } (void) mmove(dir, &y, &x); } while (!flag); } /* Light line in all directions -RAK- */ void starlite(y, x) register int y, x; { register int i; if (py.flags.blind < 1) msg_print("The end of the staff bursts into a blue shimmering light."); for (i = 1; i <= 9; i++) if (i != 5) light_line(i, y, x); } /* Disarms all traps/chests in a given direction -RAK- */ int disarm_all(dir, y, x) int dir, y, x; { register cave_type *c_ptr; register inven_type *t_ptr; register int disarm, dist; disarm = FALSE; dist = -1; do { /* put mmove at end, in case standing on a trap */ dist++; c_ptr = &cave[y][x]; /* note, must continue upto and including the first non open space, because secret doors have fval greater than MAX_OPEN_SPACE */ if (c_ptr->tptr != 0) { t_ptr = &t_list[c_ptr->tptr]; if ((t_ptr->tval == TV_INVIS_TRAP) || (t_ptr->tval == TV_VIS_TRAP)) { if (delete_object(y, x)) disarm = TRUE; } else if (t_ptr->tval == TV_CLOSED_DOOR) t_ptr->p1 = 0; /* Locked or jammed doors become merely closed. */ else if (t_ptr->tval == TV_SECRET_DOOR) { c_ptr->fm = TRUE; change_trap(y, x); disarm = TRUE; } else if ((t_ptr->tval == TV_CHEST) && (t_ptr->flags != 0)) { msg_print("Click!"); t_ptr->flags &= ~(CH_TRAPPED|CH_LOCKED); disarm = TRUE; t_ptr->name2 = SN_UNLOCKED; known2(t_ptr); } } (void) mmove(dir, &y, &x); } while ((dist <= OBJ_BOLT_RANGE) && c_ptr->fval <= MAX_OPEN_SPACE); return(disarm); } /* Return flags for given type area affect -RAK- */ void get_flags(typ, weapon_type, harm_type, destroy) int typ; int32u *weapon_type; int *harm_type; int (**destroy)(); { switch(typ) { case GF_MAGIC_MISSILE: *weapon_type = 0; *harm_type = 0; *destroy = set_null; break; case GF_LIGHTNING: *weapon_type = CS_BR_LIGHT; *harm_type = CD_LIGHT; *destroy = set_lightning_destroy; break; case GF_POISON_GAS: *weapon_type = CS_BR_GAS; *harm_type = CD_POISON; *destroy = set_null; break; case GF_ACID: *weapon_type = CS_BR_ACID; *harm_type = CD_ACID; *destroy = set_acid_destroy; break; case GF_FROST: *weapon_type = CS_BR_FROST; *harm_type = CD_FROST; *destroy = set_frost_destroy; break; case GF_FIRE: *weapon_type = CS_BR_FIRE; *harm_type = CD_FIRE; *destroy = set_fire_destroy; break; case GF_HOLY_ORB: *weapon_type = 0; *harm_type = CD_EVIL; *destroy = set_null; break; default: msg_print("ERROR in get_flags()\n"); } } /* Shoot a bolt in a given direction -RAK- */ void fire_bolt(typ, dir, y, x, dam, bolt_typ) int typ, dir, y, x, dam; char *bolt_typ; { int i, oldy, oldx, dist, flag; int32u weapon_type; int harm_type; int (*dummy)(); register cave_type *c_ptr; register monster_type *m_ptr; register creature_type *r_ptr; vtype out_val, m_name; flag = FALSE; get_flags(typ, &weapon_type, &harm_type, &dummy); oldy = y; oldx = x; dist = 0; do { (void) mmove(dir, &y, &x); dist++; c_ptr = &cave[y][x]; lite_spot(oldy, oldx); if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE) flag = TRUE; else { if (c_ptr->cptr > 1) { flag = TRUE; m_ptr = &m_list[c_ptr->cptr]; r_ptr = &c_list[m_ptr->mptr]; /* light up monster and draw monster, temporarily set pl so that update_mon() will work */ i = c_ptr->pl; c_ptr->pl = TRUE; update_mon ((int)c_ptr->cptr); c_ptr->pl = i; /* draw monster and clear previous bolt */ put_qio(); lower_monster_name(m_name, m_ptr, r_ptr); (void) sprintf(out_val, "The %s strikes %s.", bolt_typ, m_name); msg_print(out_val); if (harm_type & r_ptr->cdefense) { dam = dam*2; if (m_ptr->ml) c_recall[m_ptr->mptr].r_cdefense |= harm_type; } else if (weapon_type & r_ptr->spells) { dam = dam / 4; if (m_ptr->ml) c_recall[m_ptr->mptr].r_spells |= weapon_type; } monster_name(m_name, m_ptr, r_ptr); i = mon_take_hit((int)c_ptr->cptr, dam); if (i >= 0) { (void) sprintf(out_val, "%s dies in a fit of agony.", m_name); msg_print(out_val); prt_experience(); } else if (dam > 0) { (void) sprintf (out_val, "%s screams in agony.", m_name); msg_print (out_val); } } else if (panel_contains(y, x) && (py.flags.blind < 1)) { print('*', y, x); /* show the bolt */ put_qio(); } } oldy = y; oldx = x; } while (!flag); } /* Shoot a ball in a given direction. Note that balls have an */ /* area affect. -RAK- */ void fire_ball(typ, dir, y, x, dam_hp, descrip) int typ, dir, y, x, dam_hp; char *descrip; { register int i, j; int dam, max_dis, thit, tkill, k, tmp; int oldy, oldx, dist, flag, harm_type; int32u weapon_type; int (*destroy)(); register cave_type *c_ptr; register monster_type *m_ptr; register creature_type *r_ptr; vtype out_val; thit = 0; tkill = 0; max_dis = 2; get_flags(typ, &weapon_type, &harm_type, &destroy); flag = FALSE; oldy = y; oldx = x; dist = 0; do { (void) mmove(dir, &y, &x); dist++; lite_spot(oldy, oldx); if (dist > OBJ_BOLT_RANGE) flag = TRUE; else { c_ptr = &cave[y][x]; if ((c_ptr->fval >= MIN_CLOSED_SPACE) || (c_ptr->cptr > 1)) { flag = TRUE; if (c_ptr->fval >= MIN_CLOSED_SPACE) { y = oldy; x = oldx; } /* The ball hits and explodes. */ /* The explosion. */ for (i = y-max_dis; i <= y+max_dis; i++) for (j = x-max_dis; j <= x+max_dis; j++) if (in_bounds(i, j) && (distance(y, x, i, j) <= max_dis) && los(y, x, i, j)) { c_ptr = &cave[i][j]; if ((c_ptr->tptr != 0) && (*destroy)(&t_list[c_ptr->tptr])) (void) delete_object(i, j); if (c_ptr->fval <= MAX_OPEN_SPACE) { if (c_ptr->cptr > 1) { m_ptr = &m_list[c_ptr->cptr]; r_ptr = &c_list[m_ptr->mptr]; /* lite up creature if visible, temp set pl so that update_mon works */ tmp = c_ptr->pl; c_ptr->pl = TRUE; update_mon((int)c_ptr->cptr); thit++; dam = dam_hp; if (harm_type & r_ptr->cdefense) { dam = dam*2; if (m_ptr->ml) c_recall[m_ptr->mptr].r_cdefense |=harm_type; } else if (weapon_type & r_ptr->spells) { dam = dam / 4; if (m_ptr->ml) c_recall[m_ptr->mptr].r_spells |=weapon_type; } dam = (dam/(distance(i, j, y, x)+1)); k = mon_take_hit((int)c_ptr->cptr, dam); if (k >= 0) tkill++; c_ptr->pl = tmp; } else if (panel_contains(i, j) &&(py.flags.blind < 1)) print('*', i, j); } } /* show ball of whatever */ put_qio(); for (i = (y - 2); i <= (y + 2); i++) for (j = (x - 2); j <= (x + 2); j++) if (in_bounds(i, j) && panel_contains(i, j) && (distance(y, x, i, j) <= max_dis)) lite_spot(i, j); /* End explosion. */ if (thit == 1) { (void) sprintf(out_val, "The %s envelops a creature!", descrip); msg_print(out_val); } else if (thit > 1) { (void) sprintf(out_val, "The %s envelops several creatures!", descrip); msg_print(out_val); } if (tkill == 1) msg_print("There is a scream of agony!"); else if (tkill > 1) msg_print("There are several screams of agony!"); if (tkill >= 0) prt_experience(); /* End ball hitting. */ } else if (panel_contains(y, x) && (py.flags.blind < 1)) { print('*', y, x); /* show bolt */ put_qio(); } oldy = y; oldx = x; } } while (!flag); } /* Breath weapon works like a fire_ball, but affects the player. */ /* Note the area affect. -RAK- */ void breath(typ, y, x, dam_hp, ddesc, monptr) int typ, y, x, dam_hp; char *ddesc; int monptr; { register int i, j; int dam, max_dis, harm_type; int32u weapon_type; int32u tmp, treas; int (*destroy)(); register cave_type *c_ptr; register monster_type *m_ptr; register creature_type *r_ptr; #ifdef ATARIST_MWC int32u holder; #endif max_dis = 2; get_flags(typ, &weapon_type, &harm_type, &destroy); for (i = y-2; i <= y+2; i++) for (j = x-2; j <= x+2; j++) if (in_bounds(i, j) && (distance(y, x, i, j) <= max_dis) && los(y, x, i, j)) { c_ptr = &cave[i][j]; if ((c_ptr->tptr != 0) && (*destroy)(&t_list[c_ptr->tptr])) (void) delete_object(i, j); if (c_ptr->fval <= MAX_OPEN_SPACE) { /* must test status bit, not py.flags.blind here, flag could have been set by a previous monster, but the breath should still be visible until the blindness takes effect */ if (panel_contains(i, j) && !(py.flags.status & PY_BLIND)) print('*', i, j); if (c_ptr->cptr > 1) { m_ptr = &m_list[c_ptr->cptr]; r_ptr = &c_list[m_ptr->mptr]; dam = dam_hp; if (harm_type & r_ptr->cdefense) dam = dam*2; else if (weapon_type & r_ptr->spells) dam = (dam / 4); dam = (dam/(distance(i, j, y, x)+1)); /* can not call mon_take_hit here, since player does not get experience for kill */ m_ptr->hp = m_ptr->hp - dam; m_ptr->csleep = 0; if (m_ptr->hp < 0) { treas = monster_death((int)m_ptr->fy, (int)m_ptr->fx, r_ptr->cmove); if (m_ptr->ml) { #ifdef ATARIST_MWC holder = CM_TREASURE; tmp = (c_recall[m_ptr->mptr].r_cmove & holder) >> CM_TR_SHIFT; if (tmp > ((treas & holder) >> CM_TR_SHIFT)) treas = (treas & ~holder)|(tmp << CM_TR_SHIFT); c_recall[m_ptr->mptr].r_cmove = treas | (c_recall[m_ptr->mptr].r_cmove & ~holder); #else tmp = (c_recall[m_ptr->mptr].r_cmove & CM_TREASURE) >> CM_TR_SHIFT; if (tmp > ((treas & CM_TREASURE) >> CM_TR_SHIFT)) treas = (treas & ~CM_TREASURE)|(tmp<mptr].r_cmove = treas | (c_recall[m_ptr->mptr].r_cmove & ~CM_TREASURE); #endif } /* It ate an already processed monster.Handle normally.*/ if (monptr < c_ptr->cptr) delete_monster((int) c_ptr->cptr); /* If it eats this monster, an already processed monster will take its place, causing all kinds of havoc. Delay the kill a bit. */ else fix1_delete_monster((int) c_ptr->cptr); } } else if (c_ptr->cptr == 1) { dam = (dam_hp/(distance(i, j, y, x)+1)); /* let's do at least one point of damage */ /* prevents randint(0) problem with poison_gas, also */ if (dam == 0) dam = 1; switch(typ) { case GF_LIGHTNING: light_dam(dam, ddesc); break; case GF_POISON_GAS: poison_gas(dam, ddesc); break; case GF_ACID: acid_dam(dam, ddesc); break; case GF_FROST: cold_dam(dam, ddesc); break; case GF_FIRE: fire_dam(dam, ddesc); break; } } } } /* show the ball of gas */ put_qio(); for (i = (y - 2); i <= (y + 2); i++) for (j = (x - 2); j <= (x + 2); j++) if (in_bounds(i, j) && panel_contains(i, j) && (distance(y, x, i, j) <= max_dis)) lite_spot(i, j); } /* Recharge a wand, staff, or rod. Sometimes the item breaks. -RAK-*/ int recharge(num) register int num; { int i, j, item_val; register int res; register inven_type *i_ptr; res = FALSE; if (!find_range(TV_STAFF, TV_WAND, &i, &j)) msg_print("You have nothing to recharge."); else if (get_item(&item_val, "Recharge which item?", i, j, CNIL, CNIL)) { i_ptr = &inventory[item_val]; res = TRUE; /* recharge I = recharge(20) = 1/6 failure for empty 10th level wand */ /* recharge II = recharge(60) = 1/10 failure for empty 10th level wand*/ /* make it harder to recharge high level, and highly charged wands, note that i can be negative, so check its value before trying to call randint(). */ i = num + 50 - (int)i_ptr->level - i_ptr->p1; if (i < 19) i = 1; /* Automatic failure. */ else i = randint (i/10); if (i == 1) { msg_print("There is a bright flash of light."); inven_destroy(item_val); } else { num = (num/(i_ptr->level+2)) + 1; i_ptr->p1 += 2 + randint(num); if (known2_p(i_ptr)) clear_known2(i_ptr); clear_empty(i_ptr); } } return(res); } /* Increase or decrease a creatures hit points -RAK- */ int hp_monster(dir, y, x, dam) int dir, y, x, dam; { register int i; int flag, dist, monster; register cave_type *c_ptr; register monster_type *m_ptr; register creature_type *r_ptr; vtype out_val, m_name; monster = FALSE; flag = FALSE; dist = 0; do { (void) mmove(dir, &y, &x); dist++; c_ptr = &cave[y][x]; if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE) flag = TRUE; else if (c_ptr->cptr > 1) { flag = TRUE; m_ptr = &m_list[c_ptr->cptr]; r_ptr = &c_list[m_ptr->mptr]; monster_name (m_name, m_ptr, r_ptr); monster = TRUE; i = mon_take_hit((int)c_ptr->cptr, dam); if (i >= 0) { (void) sprintf(out_val, "%s dies in a fit of agony.", m_name); msg_print(out_val); prt_experience(); } else if (dam > 0) { (void) sprintf(out_val, "%s screams in agony.", m_name); msg_print(out_val); } } } while (!flag); return(monster); } /* Drains life; note it must be living. -RAK- */ int drain_life(dir, y, x) int dir, y, x; { register int i; int flag, dist, drain; register cave_type *c_ptr; register monster_type *m_ptr; register creature_type *r_ptr; vtype out_val, m_name; drain = FALSE; flag = FALSE; dist = 0; do { (void) mmove(dir, &y, &x); dist++; c_ptr = &cave[y][x]; if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE) flag = TRUE; else if (c_ptr->cptr > 1) { flag = TRUE; m_ptr = &m_list[c_ptr->cptr]; r_ptr = &c_list[m_ptr->mptr]; if ((r_ptr->cdefense & CD_UNDEAD) == 0) { drain = TRUE; monster_name (m_name, m_ptr, r_ptr); i = mon_take_hit((int)c_ptr->cptr, 75); if (i >= 0) { (void) sprintf(out_val, "%s dies in a fit of agony.",m_name); msg_print(out_val); prt_experience(); } else { (void) sprintf(out_val, "%s screams in agony.", m_name); msg_print(out_val); } } else c_recall[m_ptr->mptr].r_cdefense |= CD_UNDEAD; } } while (!flag); return(drain); } /* Increase or decrease a creatures speed -RAK- */ /* NOTE: cannot slow a winning creature (BALROG) */ int speed_monster(dir, y, x, spd) int dir, y, x, spd; { int flag, dist, speed; register cave_type *c_ptr; register monster_type *m_ptr; register creature_type *r_ptr; vtype out_val, m_name; speed = FALSE; flag = FALSE; dist = 0; do { (void) mmove(dir, &y, &x); dist++; c_ptr = &cave[y][x]; if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE) flag = TRUE; else if (c_ptr->cptr > 1) { flag = TRUE; m_ptr = &m_list[c_ptr->cptr]; r_ptr = &c_list[m_ptr->mptr]; monster_name (m_name, m_ptr, r_ptr); if (spd > 0) { m_ptr->cspeed += spd; m_ptr->csleep = 0; (void) sprintf (out_val, "%s starts moving faster.", m_name); msg_print (out_val); speed = TRUE; } else if (randint(MAX_MONS_LEVEL) > r_ptr->level) { m_ptr->cspeed += spd; m_ptr->csleep = 0; (void) sprintf (out_val, "%s starts moving slower.", m_name); msg_print (out_val); speed = TRUE; } else { m_ptr->csleep = 0; (void) sprintf(out_val, "%s is unaffected.", m_name); msg_print(out_val); } } } while (!flag); return(speed); } /* Confuse a creature -RAK- */ int confuse_monster(dir, y, x) int dir, y, x; { int flag, dist, confuse; register cave_type *c_ptr; register monster_type *m_ptr; register creature_type *r_ptr; vtype out_val, m_name; confuse = FALSE; flag = FALSE; dist = 0; do { (void) mmove(dir, &y, &x); dist++; c_ptr = &cave[y][x]; if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE) flag = TRUE; else if (c_ptr->cptr > 1) { m_ptr = &m_list[c_ptr->cptr]; r_ptr = &c_list[m_ptr->mptr]; monster_name (m_name, m_ptr, r_ptr); flag = TRUE; if ((randint(MAX_MONS_LEVEL) < r_ptr->level) || (CD_NO_SLEEP & r_ptr->cdefense)) { if (m_ptr->ml && (r_ptr->cdefense & CD_NO_SLEEP)) c_recall[m_ptr->mptr].r_cdefense |= CD_NO_SLEEP; /* Monsters which resisted the attack should wake up. Monsters with innate resistence ignore the attack. */ if (! (CD_NO_SLEEP & r_ptr->cdefense)) m_ptr->csleep = 0; (void) sprintf(out_val, "%s is unaffected.", m_name); msg_print(out_val); } else { if (m_ptr->confused) m_ptr->confused += 3; else m_ptr->confused = 2 + randint(16); confuse = TRUE; m_ptr->csleep = 0; (void) sprintf(out_val, "%s appears confused.", m_name); msg_print(out_val); } } } while (!flag); return(confuse); } /* Sleep a creature. -RAK- */ int sleep_monster(dir, y, x) int dir, y, x; { int flag, dist, sleep; register cave_type *c_ptr; register monster_type *m_ptr; register creature_type *r_ptr; vtype out_val, m_name; sleep = FALSE; flag = FALSE; dist = 0; do { (void) mmove(dir, &y, &x); dist++; c_ptr = &cave[y][x]; if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE) flag = TRUE; else if (c_ptr->cptr > 1) { m_ptr = &m_list[c_ptr->cptr]; r_ptr = &c_list[m_ptr->mptr]; flag = TRUE; monster_name (m_name, m_ptr, r_ptr); if ((randint(MAX_MONS_LEVEL) < r_ptr->level) || (CD_NO_SLEEP & r_ptr->cdefense)) { if (m_ptr->ml && (r_ptr->cdefense & CD_NO_SLEEP)) c_recall[m_ptr->mptr].r_cdefense |= CD_NO_SLEEP; (void) sprintf(out_val, "%s is unaffected.", m_name); msg_print(out_val); } else { m_ptr->csleep = 500; sleep = TRUE; (void) sprintf(out_val, "%s falls asleep.", m_name); msg_print(out_val); } } } while (!flag); return(sleep); } /* Turn stone to mud, delete wall. -RAK- */ int wall_to_mud(dir, y, x) int dir, y, x; { int i, wall, dist; bigvtype out_val, tmp_str; register int flag; register cave_type *c_ptr; register monster_type *m_ptr; register creature_type *r_ptr; vtype m_name; wall = FALSE; flag = FALSE; dist = 0; do { (void) mmove(dir, &y, &x); dist++; c_ptr = &cave[y][x]; /* note, this ray can move through walls as it turns them to mud */ if (dist == OBJ_BOLT_RANGE) flag = TRUE; if ((c_ptr->fval >= MIN_CAVE_WALL) && (c_ptr->fval != BOUNDARY_WALL)) { flag = TRUE; (void) twall(y, x, 1, 0); if (test_light(y, x)) { msg_print("The wall turns into mud."); wall = TRUE; } } else if ((c_ptr->tptr != 0) && (c_ptr->fval >= MIN_CLOSED_SPACE)) { flag = TRUE; if (panel_contains(y, x) && test_light(y, x)) { objdes(tmp_str, &t_list[c_ptr->tptr], FALSE); (void) sprintf(out_val, "The %s turns into mud.", tmp_str); msg_print(out_val); wall = TRUE; } if (t_list[c_ptr->tptr].tval == TV_RUBBLE) { (void) delete_object(y, x); if (randint(10) == 1) { place_object(y, x, FALSE); if (test_light(y, x)) msg_print("You have found something!"); } lite_spot(y, x); } else (void) delete_object(y, x); } if (c_ptr->cptr > 1) { m_ptr = &m_list[c_ptr->cptr]; r_ptr = &c_list[m_ptr->mptr]; if (CD_STONE & r_ptr->cdefense) { monster_name (m_name, m_ptr, r_ptr); i = mon_take_hit((int)c_ptr->cptr, 100); /* Should get these messages even if the monster is not visible. */ if (i >= 0) { c_recall[i].r_cdefense |= CD_STONE; (void) sprintf(out_val, "%s dissolves!", m_name); msg_print(out_val); prt_experience(); /* print msg before calling prt_exp */ } else { c_recall[m_ptr->mptr].r_cdefense |= CD_STONE; (void) sprintf(out_val, "%s grunts in pain!",m_name); msg_print(out_val); } flag = TRUE; } } } while (!flag); return(wall); } /* Destroy all traps and doors in a given direction -RAK- */ int td_destroy2(dir, y, x) int dir, y, x; { register int destroy2, dist; register cave_type *c_ptr; register inven_type *t_ptr; destroy2 = FALSE; dist= 0; do { (void) mmove(dir, &y, &x); dist++; c_ptr = &cave[y][x]; /* must move into first closed spot, as it might be a secret door */ if (c_ptr->tptr != 0) { t_ptr = &t_list[c_ptr->tptr]; if ((t_ptr->tval == TV_INVIS_TRAP) || (t_ptr->tval == TV_CLOSED_DOOR) || (t_ptr->tval == TV_VIS_TRAP) || (t_ptr->tval == TV_OPEN_DOOR) || (t_ptr->tval == TV_SECRET_DOOR)) { if (delete_object(y, x)) { msg_print("There is a bright flash of light!"); destroy2 = TRUE; } } else if ((t_ptr->tval == TV_CHEST) && (t_ptr->flags != 0)) { msg_print("Click!"); t_ptr->flags &= ~(CH_TRAPPED|CH_LOCKED); destroy2 = TRUE; t_ptr->name2 = SN_UNLOCKED; known2(t_ptr); } } } while ((dist <= OBJ_BOLT_RANGE) || c_ptr->fval <= MAX_OPEN_SPACE); return(destroy2); } /* Polymorph a monster -RAK- */ /* NOTE: cannot polymorph a winning creature (BALROG) */ int poly_monster(dir, y, x) int dir, y, x; { int dist, flag, poly; register cave_type *c_ptr; register creature_type *r_ptr; register monster_type *m_ptr; vtype out_val, m_name; poly = FALSE; flag = FALSE; dist = 0; do { (void) mmove(dir, &y, &x); dist++; c_ptr = &cave[y][x]; if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE) flag = TRUE; else if (c_ptr->cptr > 1) { m_ptr = &m_list[c_ptr->cptr]; r_ptr = &c_list[m_ptr->mptr]; if (randint(MAX_MONS_LEVEL) > r_ptr->level) { flag = TRUE; delete_monster((int)c_ptr->cptr); /* Place_monster() should always return TRUE here. */ poly = place_monster(y, x, randint(m_level[MAX_MONS_LEVEL]-m_level[0]) - 1 + m_level[0], FALSE); /* don't test c_ptr->fm here, only pl/tl */ if (poly && panel_contains(y, x) && (c_ptr->tl || c_ptr->pl)) poly = TRUE; } else { monster_name (m_name, m_ptr, r_ptr); (void) sprintf(out_val, "%s is unaffected.", m_name); msg_print(out_val); } } } while (!flag); return(poly); } /* Create a wall. -RAK- */ int build_wall(dir, y, x) int dir, y, x; { register int i; int build, damage, dist, flag; register cave_type *c_ptr; register monster_type *m_ptr; register creature_type *r_ptr; vtype m_name, out_val; #ifdef ATARIST_MWC int32u holder; #endif build = FALSE; dist = 0; flag = FALSE; do { (void) mmove(dir, &y, &x); dist++; c_ptr = &cave[y][x]; if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE) flag = TRUE; else { if (c_ptr->tptr != 0) (void) delete_object(y, x); if (c_ptr->cptr > 1) { /* stop the wall building */ flag = TRUE; m_ptr = &m_list[c_ptr->cptr]; r_ptr = &c_list[m_ptr->mptr]; #ifdef ATARIST_MWC if (!(r_ptr->cmove & (holder = CM_PHASE))) #else if (!(r_ptr->cmove & CM_PHASE)) #endif { /* monster does not move, can't escape the wall */ if (r_ptr->cmove & CM_ATTACK_ONLY) damage = 3000; /* this will kill everything */ else damage = damroll (4, 8); monster_name (m_name, m_ptr, r_ptr); (void) sprintf (out_val, "%s wails out in pain!", m_name); msg_print (out_val); i = mon_take_hit((int)c_ptr->cptr, damage); if (i >= 0) { (void) sprintf (out_val, "%s is embedded in the rock.", m_name); msg_print (out_val); prt_experience(); } } else if (r_ptr->cchar == 'E' || r_ptr->cchar == 'X') { /* must be an earth elemental or an earth spirit, or a Xorn increase its hit points */ m_ptr->hp += damroll(4, 8); } } c_ptr->fval = MAGMA_WALL; c_ptr->fm = FALSE; /* Permanently light this wall if it is lit by player's lamp. */ c_ptr->pl = (c_ptr->tl || c_ptr->pl); lite_spot(y, x); i++; build = TRUE; } } while (!flag); return(build); } /* Replicate a creature -RAK- */ int clone_monster(dir, y, x) int dir, y, x; { register cave_type *c_ptr; register int dist, flag; dist = 0; flag = FALSE; do { (void) mmove(dir, &y, &x); dist++; c_ptr = &cave[y][x]; if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE) flag = TRUE; else if (c_ptr->cptr > 1) { m_list[c_ptr->cptr].csleep = 0; /* monptr of 0 is safe here, since can't reach here from creatures */ return multiply_monster(y, x, (int)m_list[c_ptr->cptr].mptr, 0); } } while (!flag); return(FALSE); } /* Move the creature record to a new location -RAK- */ void teleport_away(monptr, dis) int monptr, dis; { register int yn, xn, ctr; register monster_type *m_ptr; m_ptr = &m_list[monptr]; ctr = 0; do { do { yn = m_ptr->fy + (randint(2*dis+1) - (dis + 1)); xn = m_ptr->fx + (randint(2*dis+1) - (dis + 1)); } while (!in_bounds(yn, xn)); ctr++; if (ctr > 9) { ctr = 0; dis += 5; } } while ((cave[yn][xn].fval >= MIN_CLOSED_SPACE) || (cave[yn][xn].cptr != 0)); move_rec((int)m_ptr->fy, (int)m_ptr->fx, yn, xn); lite_spot((int)m_ptr->fy, (int)m_ptr->fx); m_ptr->fy = yn; m_ptr->fx = xn; /* this is necessary, because the creature is not currently visible in its new position */ m_ptr->ml = FALSE; m_ptr->cdis = distance (char_row, char_col, yn, xn); update_mon (monptr); } /* Teleport player to spell casting creature -RAK- */ void teleport_to(ny, nx) int ny, nx; { int dis, ctr, y, x; register int i, j; register cave_type *c_ptr; dis = 1; ctr = 0; do { y = ny + (randint(2*dis+1) - (dis + 1)); x = nx + (randint(2*dis+1) - (dis + 1)); ctr++; if (ctr > 9) { ctr = 0; dis++; } } while (!in_bounds(y, x) || (cave[y][x].fval >= MIN_CLOSED_SPACE) || (cave[y][x].cptr >= 2)); move_rec(char_row, char_col, y, x); for (i = char_row-1; i <= char_row+1; i++) for (j = char_col-1; j <= char_col+1; j++) { c_ptr = &cave[i][j]; c_ptr->tl = FALSE; lite_spot(i, j); } lite_spot(char_row, char_col); char_row = y; char_col = x; check_view(); /* light creatures */ creatures(FALSE); } /* Teleport all creatures in a given direction away -RAK- */ int teleport_monster(dir, y, x) int dir, y, x; { register int flag, result, dist; register cave_type *c_ptr; flag = FALSE; result = FALSE; dist = 0; do { (void) mmove(dir, &y, &x); dist++; c_ptr = &cave[y][x]; if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE) flag = TRUE; else if (c_ptr->cptr > 1) { m_list[c_ptr->cptr].csleep = 0; /* wake it up */ teleport_away((int)c_ptr->cptr, MAX_SIGHT); result = TRUE; } } while (!flag); return(result); } /* Delete all creatures within max_sight distance -RAK- */ /* NOTE : Winning creatures cannot be genocided */ int mass_genocide() { register int i, result; register monster_type *m_ptr; register creature_type *r_ptr; #ifdef ATARIST_MWC int32u holder; #endif result = FALSE; for (i = mfptr - 1; i >= MIN_MONIX; i--) { m_ptr = &m_list[i]; r_ptr = &c_list[m_ptr->mptr]; #ifdef ATARIST_MWC if ((m_ptr->cdis <= MAX_SIGHT) && ((r_ptr->cmove & (holder = CM_WIN)) == 0)) #else if ((m_ptr->cdis <= MAX_SIGHT) && ((r_ptr->cmove & CM_WIN) == 0)) #endif { delete_monster(i); result = TRUE; } } return(result); } /* Delete all creatures of a given type from level. -RAK- */ /* This does not keep creatures of type from appearing later. */ /* NOTE : Winning creatures can not be genocided. */ int genocide() { register int i, killed; char typ; register monster_type *m_ptr; register creature_type *r_ptr; vtype out_val; #ifdef ATARIST_MWC int32u holder; #endif killed = FALSE; if (get_com("Which type of creature do you wish exterminated?", &typ)) for (i = mfptr - 1; i >= MIN_MONIX; i--) { m_ptr = &m_list[i]; r_ptr = &c_list[m_ptr->mptr]; if (typ == c_list[m_ptr->mptr].cchar) #ifdef ATARIST_MWC if ((r_ptr->cmove & (holder = CM_WIN)) == 0) #else if ((r_ptr->cmove & CM_WIN) == 0) #endif { delete_monster(i); killed = TRUE; } else { /* genocide is a powerful spell, so we will let the player know the names of the creatures he did not destroy, this message makes no sense otherwise */ (void) sprintf(out_val, "The %s is unaffected.", r_ptr->name); msg_print(out_val); } } return(killed); } /* Change speed of any creature . -RAK- */ /* NOTE: cannot slow a winning creature (BALROG) */ int speed_monsters(spd) int spd; { register int i, speed; register monster_type *m_ptr; register creature_type *r_ptr; vtype out_val, m_name; speed = FALSE; for (i = mfptr - 1; i >= MIN_MONIX; i--) { m_ptr = &m_list[i]; r_ptr = &c_list[m_ptr->mptr]; monster_name (m_name, m_ptr, r_ptr); if ((m_ptr->cdis > MAX_SIGHT) || !los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx)) /* do nothing */ ; else if (spd > 0) { m_ptr->cspeed += spd; m_ptr->csleep = 0; if (m_ptr->ml) { speed = TRUE; (void) sprintf (out_val, "%s starts moving faster.", m_name); msg_print (out_val); } } else if (randint(MAX_MONS_LEVEL) > r_ptr->level) { m_ptr->cspeed += spd; m_ptr->csleep = 0; if (m_ptr->ml) { (void) sprintf (out_val, "%s starts moving slower.", m_name); msg_print (out_val); speed = TRUE; } } else if (m_ptr->ml) { m_ptr->csleep = 0; (void) sprintf(out_val, "%s is unaffected.", m_name); msg_print(out_val); } } return(speed); } /* Sleep any creature . -RAK- */ int sleep_monsters2() { register int i, sleep; register monster_type *m_ptr; register creature_type *r_ptr; vtype out_val, m_name; sleep = FALSE; for (i = mfptr - 1; i >= MIN_MONIX; i--) { m_ptr = &m_list[i]; r_ptr = &c_list[m_ptr->mptr]; monster_name (m_name, m_ptr, r_ptr); if ((m_ptr->cdis > MAX_SIGHT) || !los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx)) /* do nothing */ ; else if ((randint(MAX_MONS_LEVEL) < r_ptr->level) || (CD_NO_SLEEP & r_ptr->cdefense)) { if (m_ptr->ml) { if (r_ptr->cdefense & CD_NO_SLEEP) c_recall[m_ptr->mptr].r_cdefense |= CD_NO_SLEEP; (void) sprintf(out_val, "%s is unaffected.", m_name); msg_print(out_val); } } else { m_ptr->csleep = 500; if (m_ptr->ml) { (void) sprintf(out_val, "%s falls asleep.", m_name); msg_print(out_val); sleep = TRUE; } } } return(sleep); } /* Polymorph any creature that player can see. -RAK- */ /* NOTE: cannot polymorph a winning creature (BALROG) */ int mass_poly() { register int i; int y, x, mass; register monster_type *m_ptr; register creature_type *r_ptr; #ifdef ATARIST_MWC int32u holder; #endif mass = FALSE; for (i = mfptr - 1; i >= MIN_MONIX; i--) { m_ptr = &m_list[i]; if (m_ptr->cdis <= MAX_SIGHT) { r_ptr = &c_list[m_ptr->mptr]; #ifdef ATARIST_MWC if ((r_ptr->cmove & (holder = CM_WIN)) == 0) #else if ((r_ptr->cmove & CM_WIN) == 0) #endif { y = m_ptr->fy; x = m_ptr->fx; delete_monster(i); /* Place_monster() should always return TRUE here. */ mass = place_monster(y, x, randint(m_level[MAX_MONS_LEVEL]-m_level[0]) - 1 + m_level[0], FALSE); } } } return(mass); } /* Display evil creatures on current panel -RAK- */ int detect_evil() { register int i, flag; register monster_type *m_ptr; flag = FALSE; for (i = mfptr - 1; i >= MIN_MONIX; i--) { m_ptr = &m_list[i]; if (panel_contains((int)m_ptr->fy, (int)m_ptr->fx) && (CD_EVIL & c_list[m_ptr->mptr].cdefense)) { m_ptr->ml = TRUE; /* works correctly even if hallucinating */ print((char)c_list[m_ptr->mptr].cchar, (int)m_ptr->fy, (int)m_ptr->fx); flag = TRUE; } } if (flag) { msg_print("You sense the presence of evil!"); msg_print(CNIL); /* must unlight every monster just lighted */ creatures(FALSE); } return(flag); } /* Change players hit points in some manner -RAK- */ int hp_player(num) int num; { register int res; register struct misc *m_ptr; res = FALSE; m_ptr = &py.misc; if (m_ptr->chp < m_ptr->mhp) { m_ptr->chp += num; if (m_ptr->chp > m_ptr->mhp) { m_ptr->chp = m_ptr->mhp; m_ptr->chp_frac = 0; } prt_chp(); num = num / 5; if (num < 3) { if (num == 0) msg_print("You feel a little better."); else msg_print("You feel better."); } else { if (num < 7) msg_print("You feel much better."); else msg_print("You feel very good."); } res = TRUE; } return(res); } /* Cure players confusion -RAK- */ int cure_confusion() { register int cure; register struct flags *f_ptr; cure = FALSE; f_ptr = &py.flags; if (f_ptr->confused > 1) { f_ptr->confused = 1; cure = TRUE; } return(cure); } /* Cure players blindness -RAK- */ int cure_blindness() { register int cure; register struct flags *f_ptr; cure = FALSE; f_ptr = &py.flags; if (f_ptr->blind > 1) { f_ptr->blind = 1; cure = TRUE; } return(cure); } /* Cure poisoning -RAK- */ int cure_poison() { register int cure; register struct flags *f_ptr; cure = FALSE; f_ptr = &py.flags; if (f_ptr->poisoned > 1) { f_ptr->poisoned = 1; cure = TRUE; } return(cure); } /* Cure the players fear -RAK- */ int remove_fear() { register int result; register struct flags *f_ptr; result = FALSE; f_ptr = &py.flags; if (f_ptr->afraid > 1) { f_ptr->afraid = 1; result = TRUE; } return(result); } /* This is a fun one. In a given block, pick some walls and */ /* turn them into open spots. Pick some open spots and turn */ /* them into walls. An "Earthquake" effect. -RAK- */ void earthquake() { register int i, j; register cave_type *c_ptr; register monster_type *m_ptr; register creature_type *r_ptr; int damage, tmp; vtype out_val, m_name; #ifdef ATARIST_MWC int32u holder; #endif for (i = char_row-8; i <= char_row+8; i++) for (j = char_col-8; j <= char_col+8; j++) if (((i != char_row) || (j != char_col)) && in_bounds(i, j) && (randint(8) == 1)) { c_ptr = &cave[i][j]; if (c_ptr->tptr != 0) (void) delete_object(i, j); if (c_ptr->cptr > 1) { m_ptr = &m_list[c_ptr->cptr]; r_ptr = &c_list[m_ptr->mptr]; #ifdef ATARIST_MWC if (!(r_ptr->cmove & (holder = CM_PHASE))) #else if (!(r_ptr->cmove & CM_PHASE)) #endif { if(r_ptr->cmove & CM_ATTACK_ONLY) damage = 3000; /* this will kill everything */ else damage = damroll (4, 8); monster_name (m_name, m_ptr, r_ptr); (void) sprintf (out_val, "%s wails out in pain!", m_name); msg_print (out_val); i = mon_take_hit((int)c_ptr->cptr, damage); if (i >= 0) { (void) sprintf (out_val, "%s is embedded in the rock.", m_name); msg_print (out_val); prt_experience(); } } else if (r_ptr->cchar == 'E' || r_ptr->cchar == 'X') { /* must be an earth elemental or an earth spirit, or a Xorn increase its hit points */ m_ptr->hp += damroll(4, 8); } } if ((c_ptr->fval >= MIN_CAVE_WALL) && (c_ptr->fval != BOUNDARY_WALL)) { c_ptr->fval = CORR_FLOOR; c_ptr->pl = FALSE; c_ptr->fm = FALSE; } else if (c_ptr->fval <= MAX_CAVE_FLOOR) { tmp = randint(10); if (tmp < 6) c_ptr->fval = QUARTZ_WALL; else if (tmp < 9) c_ptr->fval = MAGMA_WALL; else c_ptr->fval = GRANITE_WALL; c_ptr->fm = FALSE; } lite_spot(i, j); } } /* Evil creatures don't like this. -RAK- */ int protect_evil() { register int res; register struct flags *f_ptr; f_ptr = &py.flags; if (f_ptr->protevil == 0) res = TRUE; else res = FALSE; f_ptr->protevil += randint(25) + 3*py.misc.lev; return(res); } /* Create some high quality mush for the player. -RAK- */ void create_food() { register cave_type *c_ptr; c_ptr = &cave[char_row][char_col]; if (c_ptr->tptr != 0) { /* take no action here, don't want to destroy object under player */ msg_print ("There is already an object under you."); /* set free_turn_flag so that scroll/spell points won't be used */ free_turn_flag = TRUE; } else { place_object(char_row, char_col, FALSE); invcopy(&t_list[c_ptr->tptr], OBJ_MUSH); } } /* Attempts to destroy a type of creature. Success depends on */ /* the creatures level VS. the player's level -RAK- */ int dispel_creature(cflag, damage) int cflag; int damage; { register int i; int k, dispel; register monster_type *m_ptr; register creature_type *r_ptr; vtype out_val, m_name; dispel = FALSE; for (i = mfptr - 1; i >= MIN_MONIX; i--) { m_ptr = &m_list[i]; if ((m_ptr->cdis <= MAX_SIGHT) && (cflag & c_list[m_ptr->mptr].cdefense) && los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx)) { r_ptr = &c_list[m_ptr->mptr]; c_recall[m_ptr->mptr].r_cdefense |= cflag; monster_name (m_name, m_ptr, r_ptr); k = mon_take_hit (i, randint(damage)); /* Should get these messages even if the monster is not visible. */ if (k >= 0) (void) sprintf(out_val, "%s dissolves!", m_name); else (void) sprintf(out_val, "%s shudders.", m_name); msg_print(out_val); dispel = TRUE; if (k >= 0) prt_experience(); } } return(dispel); } /* Attempt to turn (confuse) undead creatures. -RAK- */ int turn_undead() { register int i, turn_und; register monster_type *m_ptr; register creature_type *r_ptr; vtype out_val, m_name; turn_und = FALSE; for (i = mfptr - 1; i >= MIN_MONIX; i--) { m_ptr = &m_list[i]; r_ptr = &c_list[m_ptr->mptr]; if ((m_ptr->cdis <= MAX_SIGHT) && (CD_UNDEAD & r_ptr->cdefense) && (los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx))) { monster_name (m_name, m_ptr, r_ptr); if (((py.misc.lev+1) > r_ptr->level) || (randint(5) == 1)) { if (m_ptr->ml) { (void) sprintf(out_val, "%s runs frantically!", m_name); msg_print(out_val); turn_und = TRUE; c_recall[m_ptr->mptr].r_cdefense |= CD_UNDEAD; } m_ptr->confused = py.misc.lev; } else if (m_ptr->ml) { (void) sprintf(out_val, "%s is unaffected.", m_name); msg_print(out_val); } } } return(turn_und); } /* Leave a glyph of warding. Creatures will not pass over! -RAK-*/ void warding_glyph() { register int i; register cave_type *c_ptr; c_ptr = &cave[char_row][char_col]; if (c_ptr->tptr == 0) { i = popt(); c_ptr->tptr = i; invcopy(&t_list[i], OBJ_SCARE_MON); } } /* Lose a strength point. -RAK- */ void lose_str() { if (!py.flags.sustain_str) { (void) dec_stat (A_STR); msg_print("You feel very sick."); } else msg_print("You feel sick for a moment, it passes."); } /* Lose an intelligence point. -RAK- */ void lose_int() { if (!py.flags.sustain_int) { (void) dec_stat(A_INT); msg_print("You become very dizzy."); } else msg_print("You become dizzy for a moment, it passes."); } /* Lose a wisdom point. -RAK- */ void lose_wis() { if (!py.flags.sustain_wis) { (void) dec_stat(A_WIS); msg_print("You feel very naive."); } else msg_print("You feel naive for a moment, it passes."); } /* Lose a dexterity point. -RAK- */ void lose_dex() { if (!py.flags.sustain_dex) { (void) dec_stat(A_DEX); msg_print("You feel very sore."); } else msg_print("You feel sore for a moment, it passes."); } /* Lose a constitution point. -RAK- */ void lose_con() { if (!py.flags.sustain_con) { (void) dec_stat(A_CON); msg_print("You feel very sick."); } else msg_print("You feel sick for a moment, it passes."); } /* Lose a charisma point. -RAK- */ void lose_chr() { if (!py.flags.sustain_chr) { (void) dec_stat(A_CHR); msg_print("Your skin starts to itch."); } else msg_print("Your skin starts to itch, but feels better now."); } /* Lose experience -RAK- */ void lose_exp(amount) int32 amount; { register int i; register struct misc *m_ptr; register class_type *c_ptr; m_ptr = &py.misc; if (amount > m_ptr->exp) m_ptr->exp = 0; else m_ptr->exp -= amount; prt_experience(); i = 0; while ((player_exp[i] * m_ptr->expfact / 100) <= m_ptr->exp) i++; /* increment i once more, because level 1 exp is stored in player_exp[0] */ i++; if (m_ptr->lev != i) { m_ptr->lev = i; calc_hitpoints(); c_ptr = &class[m_ptr->pclass]; if (c_ptr->spell == MAGE) { calc_spells(A_INT); calc_mana(A_INT); } else if (c_ptr->spell == PRIEST) { calc_spells(A_WIS); calc_mana(A_WIS); } prt_level(); prt_title(); } } /* Slow Poison -RAK- */ int slow_poison() { register int slow; register struct flags *f_ptr; slow = FALSE; f_ptr = &py.flags; if (f_ptr->poisoned > 0) { f_ptr->poisoned = f_ptr->poisoned / 2; if (f_ptr->poisoned < 1) f_ptr->poisoned = 1; slow = TRUE; msg_print("The effect of the poison has been reduced."); } return(slow); } /* Bless -RAK- */ void bless(amount) int amount; { py.flags.blessed += amount; } /* Detect Invisible for period of time -RAK- */ void detect_inv2(amount) int amount; { py.flags.detect_inv += amount; } static void replace_spot(y, x, typ) int y, x, typ; { register cave_type *c_ptr; c_ptr = &cave[y][x]; switch(typ) { case 1: case 2: case 3: c_ptr->fval = CORR_FLOOR; break; case 4: case 7: case 10: c_ptr->fval = GRANITE_WALL; break; case 5: case 8: case 11: c_ptr->fval = MAGMA_WALL; break; case 6: case 9: case 12: c_ptr->fval = QUARTZ_WALL; break; } c_ptr->pl = FALSE; c_ptr->fm = FALSE; c_ptr->lr = FALSE; /* this is no longer part of a room */ if (c_ptr->tptr != 0) (void) delete_object(y, x); if (c_ptr->cptr > 1) delete_monster((int)c_ptr->cptr); } /* The spell of destruction. -RAK- */ /* NOTE : Winning creatures that are deleted will be considered */ /* as teleporting to another level. This will NOT win the*/ /* game. */ void destroy_area(y, x) register int y, x; { register int i, j, k; if (dun_level > 0) { for (i = (y-15); i <= (y+15); i++) for (j = (x-15); j <= (x+15); j++) if (in_bounds(i, j) && (cave[i][j].fval != BOUNDARY_WALL)) { k = distance(i, j, y, x); if (k == 0) /* clear player's spot, but don't put wall there */ replace_spot(i, j, 1); else if (k < 13) replace_spot(i, j, randint(6)); else if (k < 16) replace_spot(i, j, randint(9)); } } msg_print("There is a searing blast of light!"); py.flags.blind += 10 + randint(10); } /* Enchants a plus onto an item. -RAK- */ int enchant(plusses, limit) int16 *plusses; int16 limit; /* maximum bonus allowed; usually 10, but weapon's maximum damage when enchanting melee weapons to damage */ { register int chance, res; if (limit <= 0) /* avoid randint(0) call */ return(FALSE); chance = 0; res = FALSE; if (*plusses > 0) { chance = *plusses; if (randint(100) == 1) /* very rarely allow enchantment over limit */ chance = randint(chance) - 1; } if (randint(limit) > chance) { *plusses += 1; res = TRUE; } return(res); } /* Removes curses from items in inventory -RAK- */ int remove_curse() { register int i, result; register inven_type *i_ptr; #ifdef ATARIST_MWC int32u holder = TR_CURSED; #endif result = FALSE; for (i = INVEN_WIELD; i <= INVEN_OUTER; i++) { i_ptr = &inventory[i]; #ifdef ATARIST_MWC if (holder & i_ptr->flags) #else if (TR_CURSED & i_ptr->flags) #endif { #ifdef ATARIST_MWC i_ptr->flags &= ~holder; #else i_ptr->flags &= ~TR_CURSED; #endif calc_bonuses(); result = TRUE; } } return(result); } /* Restores any drained experience -RAK- */ int restore_level() { register int restore; register struct misc *m_ptr; restore = FALSE; m_ptr = &py.misc; if (m_ptr->max_exp > m_ptr->exp) { restore = TRUE; msg_print("You feel your life energies returning."); /* this while loop is not redundant, ptr_exp may reduce the exp level */ while (m_ptr->exp < m_ptr->max_exp) { m_ptr->exp = m_ptr->max_exp; prt_experience(); } } return(restore); } moria-5.6.debian.1/source/store2.c0000644000175000017500000007210311074756544015065 0ustar pjbpjb/* source/store2.c: store code, entering, command interpreter, buying, selling Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include #include #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #ifdef USG #ifndef ATARIST_MWC #include #endif #else #include #endif #if defined(LINT_ARGS) static void prt_comment1(void); static void prt_comment2(int32, int32, int); static void prt_comment3(int32, int32, int); static void prt_comment4(void); static void prt_comment5(void); static void prt_comment6(void); static void display_commands(void); static void haggle_commands(int); static void display_inventory(int, int); static void display_cost(int, int); static void store_prt_gold(void); static void display_store(int, int); static int get_store_item(int *, char *, int, int); static int increase_insults(int); static void decrease_insults(int); static int haggle_insults(int); static int get_haggle(char *, int32 *, int); static int receive_offer(int, char *, int32 *, int32, int, int); static int purchase_haggle(int, int32 *, struct inven_type *); static int sell_haggle(int, int32 *, struct inven_type *); static int store_purchase(int, int *); static int store_sell(int, int *); #endif #ifdef ATARIST_TC /* Include this to get prototypes for standard library functions. */ #include #endif long atol(); static char *comment1[14] = { "Done!", "Accepted!", "Fine.", "Agreed!", "Ok.", "Taken!", "You drive a hard bargain, but taken.", "You'll force me bankrupt, but it's a deal.", "Sigh. I'll take it.", "My poor sick children may starve, but done!", "Finally! I accept.", "Robbed again.", "A pleasure to do business with you!", "My spouse will skin me, but accepted." }; static char *comment2a[3] = { "%A2 is my final offer; take it or leave it.", "I'll give you no more than %A2.", "My patience grows thin. %A2 is final." }; static char *comment2b[16] = { "%A1 for such a fine item? HA! No less than %A2.", "%A1 is an insult! Try %A2 gold pieces.", "%A1?!? You would rob my poor starving children?", "Why, I'll take no less than %A2 gold pieces.", "Ha! No less than %A2 gold pieces.", "Thou knave! No less than %A2 gold pieces.", "%A1 is far too little, how about %A2?", "I paid more than %A1 for it myself, try %A2.", "%A1? Are you mad?!? How about %A2 gold pieces?", "As scrap this would bring %A1. Try %A2 in gold.", "May the fleas of 1000 orcs molest you. I want %A2.", "My mother you can get for %A1, this costs %A2.", "May your chickens grow lips. I want %A2 in gold!", "Sell this for such a pittance? Give me %A2 gold.", "May the Balrog find you tasty! %A2 gold pieces?", "Your mother was a Troll! %A2 or I'll tell." }; static char *comment3a[3] = { "I'll pay no more than %A1; take it or leave it.", "You'll get no more than %A1 from me.", "%A1 and that's final." }; static char *comment3b[15] = { "%A2 for that piece of junk? No more than %A1.", "For %A2 I could own ten of those. Try %A1.", "%A2? NEVER! %A1 is more like it.", "Let's be reasonable. How about %A1 gold pieces?", "%A1 gold for that junk, no more.", "%A1 gold pieces and be thankful for it!", "%A1 gold pieces and not a copper more.", "%A2 gold? HA! %A1 is more like it.", "Try about %A1 gold.", "I wouldn't pay %A2 for your children, try %A1.", "*CHOKE* For that!? Let's say %A1.", "How about %A1?", "That looks war surplus! Say %A1 gold.", "I'll buy it as scrap for %A1.", "%A2 is too much, let us say %A1 gold." }; static char *comment4a[5] = { "ENOUGH! You have abused me once too often!", "THAT DOES IT! You shall waste my time no more!", "This is getting nowhere. I'm going home!", "BAH! No more shall you insult me!", "Begone! I have had enough abuse for one day." }; static char *comment4b[5] = { "Out of my place!", "out... Out... OUT!!!", "Come back tomorrow.", "Leave my place. Begone!", "Come back when thou art richer." }; static char *comment5[10] = { "You will have to do better than that!", "That's an insult!", "Do you wish to do business or not?", "Hah! Try again.", "Ridiculous!", "You've got to be kidding!", "You'd better be kidding!", "You try my patience.", "I don't hear you.", "Hmmm, nice weather we're having." }; static char *comment6[5] = { "I must have heard you wrong.", "What was that?", "I'm sorry, say that again.", "What did you say?", "Sorry, what was that again?" }; extern int16 last_store_inc; /* Comments vary. -RAK- */ /* Comment one : Finished haggling */ static void prt_comment1() { msg_print(comment1[randint(14)-1]); } /* %A1 is offer, %A2 is asking. */ static void prt_comment2(offer, asking, final) int32 offer, asking; int final; { vtype comment; if (final > 0) (void) strcpy(comment, comment2a[randint(3)-1]); else (void) strcpy(comment, comment2b[randint(16)-1]); insert_lnum(comment, "%A1", offer, FALSE); insert_lnum(comment, "%A2", asking, FALSE); msg_print(comment); } static void prt_comment3(offer, asking, final) int32 offer, asking; int final; { vtype comment; if (final > 0) (void) strcpy (comment, comment3a[randint(3)-1]); else (void) strcpy (comment, comment3b[randint(15)-1]); insert_lnum(comment, "%A1", offer, FALSE); insert_lnum(comment, "%A2", asking, FALSE); msg_print(comment); } /* Kick 'da bum out. -RAK- */ static void prt_comment4() { register int tmp; tmp = randint(5) - 1; msg_print(comment4a[tmp]); msg_print(comment4b[tmp]); } static void prt_comment5() { msg_print(comment5[randint(10)-1]); } static void prt_comment6() { msg_print (comment6[randint(5)-1]); } /* Displays the set of commands -RAK- */ static void display_commands() { prt("You may:", 20, 0); prt(" p) Purchase an item. b) Browse store's inventory.", 21, 0); prt(" s) Sell an item. i/e/t/w/x) Inventory/Equipment Lists.", 22, 0); prt("ESC) Exit from Building. ^R) Redraw the screen.", 23, 0); } /* Displays the set of commands -RAK- */ static void haggle_commands(typ) int typ; { if (typ == -1) prt("Specify an asking-price in gold pieces.", 21, 0); else prt("Specify an offer in gold pieces.", 21, 0); prt("ESC) Quit Haggling.", 22, 0); erase_line (23, 0); /* clear last line */ } /* Displays a store's inventory -RAK- */ static void display_inventory(store_num, start) int store_num, start; { register store_type *s_ptr; register inven_type *i_ptr; register int i, j, stop; bigvtype out_val1, out_val2; int32 x; s_ptr = &store[store_num]; i = (start % 12); stop = ((start / 12) + 1) * 12; if (stop > s_ptr->store_ctr) stop = s_ptr->store_ctr; while (start < stop) { i_ptr = &s_ptr->store_inven[start].sitem; x = i_ptr->number; if ((i_ptr->subval >= ITEM_SINGLE_STACK_MIN) && (i_ptr->subval <= ITEM_SINGLE_STACK_MAX)) i_ptr->number = 1; objdes(out_val1, i_ptr, TRUE); i_ptr->number = x; (void) sprintf(out_val2, "%c) %s", 'a'+i, out_val1); prt(out_val2, i+5, 0); x = s_ptr->store_inven[start].scost; if (x <= 0) { int32 value = -x; value = value * chr_adj() / 100; if (value <= 0) value = 1; (void) sprintf(out_val2, "%9ld", value); } else (void) sprintf(out_val2,"%9ld [Fixed]", x); prt(out_val2, i+5, 59); i++; start++; } if (i < 12) for (j = 0; j < (11 - i + 1); j++) erase_line (j+i+5, 0); /* clear remaining lines */ if (s_ptr->store_ctr > 12) put_buffer("- cont. -", 17, 60); else erase_line (17, 60); } /* Re-displays only a single cost -RAK- */ static void display_cost(store_num, pos) int store_num, pos; { register int i; register int32 j; vtype out_val; register store_type *s_ptr; s_ptr = &store[store_num]; i = (pos % 12); if (s_ptr->store_inven[pos].scost < 0) { j = - s_ptr->store_inven[pos].scost; j = j * chr_adj() / 100; (void) sprintf(out_val, "%ld", j); } else (void) sprintf(out_val, "%9ld [Fixed]", s_ptr->store_inven[pos].scost); prt(out_val, i+5, 59); } /* Displays players gold -RAK- */ static void store_prt_gold() { vtype out_val; (void) sprintf(out_val, "Gold Remaining : %ld", py.misc.au); prt(out_val, 18, 17); } /* Displays store -RAK- */ static void display_store(store_num, cur_top) int store_num, cur_top; { register store_type *s_ptr; s_ptr = &store[store_num]; clear_screen(); put_buffer(owners[s_ptr->owner].owner_name, 3, 9); put_buffer("Item", 4, 3); put_buffer("Asking Price", 4, 60); store_prt_gold(); display_commands(); display_inventory(store_num, cur_top); } /* Get the ID of a store item and return it's value -RAK- */ static int get_store_item(com_val, pmt, i, j) int *com_val; char *pmt; register int i, j; { char command; vtype out_val; register int flag; *com_val = -1; flag = FALSE; (void) sprintf(out_val, "(Items %c-%c, ESC to exit) %s", i+'a', j+'a', pmt); while (get_com(out_val, &command)) { command -= 'a'; if (command >= i && command <= j) { flag = TRUE; *com_val = command; break; } bell(); } erase_line(MSG_LINE, 0); return(flag); } /* Increase the insult counter and get angry if too many -RAK- */ static int increase_insults(store_num) int store_num; { register int increase; register store_type *s_ptr; increase = FALSE; s_ptr = &store[store_num]; s_ptr->insult_cur++; if (s_ptr->insult_cur > owners[s_ptr->owner].insult_max) { prt_comment4(); s_ptr->insult_cur = 0; s_ptr->bad_buy++; s_ptr->store_open = turn + 2500 + randint(2500); increase = TRUE; } return(increase); } /* Decrease insults -RAK- */ static void decrease_insults(store_num) int store_num; { register store_type *s_ptr; s_ptr = &store[store_num]; if (s_ptr->insult_cur != 0) s_ptr->insult_cur--; } /* Have insulted while haggling -RAK- */ static int haggle_insults(store_num) int store_num; { register int haggle; haggle = FALSE; if (increase_insults(store_num)) haggle = TRUE; else { prt_comment5(); msg_print (CNIL); /* keep insult separate from rest of haggle */ } return(haggle); } static int get_haggle(comment, new_offer, num_offer) char *comment; int32 *new_offer; int num_offer; { register int32 i; vtype out_val, default_offer; register int flag, clen; int orig_clen; register char *p; int increment; flag = TRUE; increment = FALSE; clen = strlen(comment); orig_clen = clen; if (num_offer == 0) last_store_inc = 0; i = 0; do { prt(comment, 0, 0); if (num_offer && last_store_inc != 0) { (void) sprintf (default_offer, "[%c%d] ", (last_store_inc < 0) ? '-' : '+', abs (last_store_inc)); prt (default_offer, 0, orig_clen); clen = orig_clen + strlen (default_offer); } if (!get_string(out_val, 0, clen, 40)) flag = FALSE; for (p = out_val; *p == ' '; p++) ; if (*p == '+' || *p == '-') increment = TRUE; if (num_offer && increment) { i = atol (out_val); /* Don't accept a zero here. Turn off increment if it was zero because a zero will not exit. This can be zero if the user did not type a number after the +/- sign. */ if (i == 0) increment = FALSE; else last_store_inc = i; } else if (num_offer && *out_val == '\0') { i = last_store_inc; increment = TRUE; } else i = atol (out_val); /* don't allow incremental haggling, if player has not made an offer yet */ if (flag && num_offer == 0 && increment) { msg_print("You haven't even made your first offer yet!"); i = 0; increment = FALSE; } } while (flag && (i == 0)); if (flag) { if (increment) *new_offer += i; else *new_offer = i; } else erase_line (0, 0); return(flag); } static int receive_offer(store_num, comment, new_offer, last_offer, num_offer, factor) int store_num; char *comment; register int32 *new_offer, last_offer; int num_offer, factor; { register int flag; register int receive; receive = 0; flag = FALSE; do { if (get_haggle(comment, new_offer, num_offer)) { if (*new_offer*factor >= last_offer*factor) flag = TRUE; else if (haggle_insults(store_num)) { receive = 2; flag = TRUE; } else /* new_offer rejected, reset new_offer so that incremental haggling works correctly */ *new_offer = last_offer; } else { receive = 1; flag = TRUE; } } while (!flag); return(receive); } /* Haggling routine -RAK- */ static int purchase_haggle(store_num, price, item) int store_num; int32 *price; inven_type *item; { int32 max_sell, min_sell, max_buy; int32 cost, cur_ask, final_ask, min_offer; int32 last_offer, new_offer; int32 x1, x2, x3; int32 min_per, max_per; register int flag, loop_flag; char *comment; vtype out_val; int purchase, num_offer, final_flag, didnt_haggle; register store_type *s_ptr; register owner_type *o_ptr; flag = FALSE; purchase = 0; *price = 0; final_flag = 0; didnt_haggle = FALSE; s_ptr = &store[store_num]; o_ptr = &owners[s_ptr->owner]; cost = sell_price(store_num, &max_sell, &min_sell, item); max_sell = max_sell * chr_adj() / 100; if (max_sell <= 0) max_sell = 1; min_sell = min_sell * chr_adj() / 100; if (min_sell <= 0) min_sell = 1; /* cast max_inflate to signed so that subtraction works correctly */ max_buy = cost * (200 - (int)o_ptr->max_inflate) / 100; if (max_buy <= 0) max_buy = 1; min_per = o_ptr->haggle_per; max_per = min_per * 3; haggle_commands(1); cur_ask = max_sell; final_ask = min_sell; min_offer = max_buy; last_offer = min_offer; new_offer = 0; num_offer = 0; /* this prevents incremental haggling on first try */ comment = "Asking"; /* go right to final price if player has bargained well */ if (noneedtobargain(store_num, final_ask)) { msg_print("After a long bargaining session, you agree upon the price."); cur_ask = min_sell; comment = "Final offer"; didnt_haggle = TRUE; /* Set up automatic increment, so that a return will accept the final price. */ last_store_inc = min_sell; num_offer = 1; } do { do { loop_flag = TRUE; (void) sprintf(out_val, "%s : %ld", comment, cur_ask); put_buffer(out_val, 1, 0); purchase = receive_offer(store_num, "What do you offer? ", &new_offer, last_offer, num_offer, 1); if (purchase != 0) flag = TRUE; else { if (new_offer > cur_ask) { prt_comment6(); /* rejected, reset new_offer for incremental haggling */ new_offer = last_offer; /* If the automatic increment is large enough to overflow, then the player must have made a mistake. Clear it because it is useless. */ if (last_offer + last_store_inc > cur_ask) last_store_inc = 0; } else if (new_offer == cur_ask) { flag = TRUE; *price = new_offer; } else loop_flag = FALSE; } } while (!flag && loop_flag); if (!flag) { x1 = (new_offer - last_offer) * 100 / (cur_ask - last_offer); if (x1 < min_per) { flag = haggle_insults(store_num); if (flag) purchase = 2; } else if (x1 > max_per) { x1 = x1 * 75 / 100; if (x1 < max_per) x1 = max_per; } x2 = x1 + randint(5) - 3; x3 = ((cur_ask - new_offer) * x2 / 100) + 1; /* don't let the price go up */ if (x3 < 0) x3 = 0; cur_ask -= x3; if (cur_ask < final_ask) { cur_ask = final_ask; comment = "Final Offer"; /* Set the automatic haggle increment so that RET will give a new_offer equal to the final_ask price. */ last_store_inc = final_ask - new_offer; final_flag++; if (final_flag > 3) { if (increase_insults(store_num)) purchase = 2; else purchase = 1; flag = TRUE; } } else if (new_offer >= cur_ask) { flag = TRUE; *price = new_offer; } if (!flag) { last_offer = new_offer; num_offer++; /* enable incremental haggling */ erase_line (1, 0); (void) sprintf(out_val, "Your last offer : %ld", last_offer); put_buffer(out_val, 1, 39); prt_comment2(last_offer, cur_ask, final_flag); /* If the current increment would take you over the store's price, then decrease it to an exact match. */ if (cur_ask - last_offer < last_store_inc) last_store_inc = cur_ask - last_offer; } } } while (!flag); /* update bargaining info */ if ((purchase == 0) && (!didnt_haggle)) updatebargain(store_num, *price, final_ask); return(purchase); } /* Haggling routine -RAK- */ static int sell_haggle(store_num, price, item) int store_num; int32 *price; inven_type *item; { int32 max_sell, max_buy, min_buy; int32 cost, cur_ask, final_ask, min_offer; int32 last_offer, new_offer; int32 max_gold; int32 x1, x2, x3; int32 min_per, max_per; register int flag, loop_flag; char *comment; vtype out_val; register store_type *s_ptr; register owner_type *o_ptr; int sell, num_offer, final_flag, didnt_haggle; flag = FALSE; sell = 0; *price = 0; final_flag = 0; didnt_haggle = FALSE; s_ptr = &store[store_num]; cost = item_value(item); if (cost < 1) { sell = 3; flag = TRUE; } else { o_ptr = &owners[s_ptr->owner]; cost = cost * (200 - chr_adj()) / 100; cost = cost * (200 - rgold_adj[o_ptr->owner_race][py.misc.prace]) / 100; if (cost < 1) cost = 1; max_sell = cost * o_ptr->max_inflate / 100; /* cast max_inflate to signed so that subtraction works correctly */ max_buy = cost * (200 - (int)o_ptr->max_inflate) / 100; min_buy = cost * (200 - o_ptr->min_inflate) / 100; if (min_buy < 1) min_buy = 1; if (max_buy < 1) max_buy = 1; if (min_buy < max_buy) min_buy = max_buy; min_per = o_ptr->haggle_per; max_per = min_per * 3; max_gold = o_ptr->max_cost; } if (!flag) { haggle_commands(-1); num_offer = 0; /* this prevents incremental haggling on first try */ if (max_buy > max_gold) { final_flag= 1; comment = "Final Offer"; /* Disable the automatic haggle increment on RET. */ last_store_inc = 0; cur_ask = max_gold; final_ask = max_gold; msg_print("I am sorry, but I have not the money to afford such \ a fine item."); didnt_haggle = TRUE; } else { cur_ask = max_buy; final_ask = min_buy; if (final_ask > max_gold) final_ask = max_gold; comment = "Offer"; /* go right to final price if player has bargained well */ if (noneedtobargain(store_num, final_ask)) { msg_print("After a long bargaining session, you agree upon \ the price."); cur_ask = final_ask; comment = "Final offer"; didnt_haggle = TRUE; /* Set up automatic increment, so that a return will accept the final price. */ last_store_inc = final_ask; num_offer = 1; } } min_offer = max_sell; last_offer = min_offer; new_offer = 0; if (cur_ask < 1) cur_ask = 1; do { do { loop_flag = TRUE; (void) sprintf(out_val, "%s : %ld", comment, cur_ask); put_buffer(out_val, 1, 0); sell = receive_offer(store_num, "What price do you ask? ", &new_offer, last_offer, num_offer, -1); if (sell != 0) flag = TRUE; else { if (new_offer < cur_ask) { prt_comment6(); /* rejected, reset new_offer for incremental haggling */ new_offer = last_offer; /* If the automatic increment is large enough to overflow, then the player must have made a mistake. Clear it because it is useless. */ if (last_offer + last_store_inc < cur_ask) last_store_inc = 0; } else if (new_offer == cur_ask) { flag = TRUE; *price = new_offer; } else loop_flag = FALSE; } } while (!flag && loop_flag); if (!flag) { x1 = (last_offer - new_offer) * 100 / (last_offer - cur_ask); if (x1 < min_per) { flag = haggle_insults(store_num); if (flag) sell = 2; } else if (x1 > max_per) { x1 = x1 * 75 / 100; if (x1 < max_per) x1 = max_per; } x2 = x1 + randint(5) - 3; x3 = ((new_offer - cur_ask) * x2 / 100) + 1; /* don't let the price go down */ if (x3 < 0) x3 = 0; cur_ask += x3; if (cur_ask > final_ask) { cur_ask = final_ask; comment = "Final Offer"; /* Set the automatic haggle increment so that RET will give a new_offer equal to the final_ask price. */ last_store_inc = final_ask - new_offer; final_flag++; if (final_flag > 3) { if (increase_insults(store_num)) sell = 2; else sell = 1; flag = TRUE; } } else if (new_offer <= cur_ask) { flag = TRUE; *price = new_offer; } if (!flag) { last_offer = new_offer; num_offer++; /* enable incremental haggling */ erase_line (1, 0); (void) sprintf(out_val, "Your last bid %ld", last_offer); put_buffer(out_val, 1, 39); prt_comment3(cur_ask, last_offer, final_flag); /* If the current decrement would take you under the store's price, then increase it to an exact match. */ if (cur_ask - last_offer > last_store_inc) last_store_inc = cur_ask - last_offer; } } } while (!flag); } /* update bargaining info */ if ((sell == 0) && (!didnt_haggle)) updatebargain(store_num, *price, final_ask); return(sell); } /* Buy an item from a store -RAK- */ static int store_purchase(store_num, cur_top) int store_num; int *cur_top; { int32 price; register int i, choice; bigvtype out_val, tmp_str; register store_type *s_ptr; inven_type sell_obj; register inven_record *r_ptr; int item_val, item_new, purchase; purchase = FALSE; s_ptr = &store[store_num]; /* i == number of objects shown on screen */ if (*cur_top == 12) i = s_ptr->store_ctr - 1 - 12; else if (s_ptr->store_ctr > 11) i = 11; else i = s_ptr->store_ctr - 1; if (s_ptr->store_ctr < 1) msg_print("I am currently out of stock."); /* Get the item number to be bought */ else if (get_store_item(&item_val, "Which item are you interested in? ", 0, i)) { item_val = item_val + *cur_top; /* TRUE item_val */ take_one_item(&sell_obj, &s_ptr->store_inven[item_val].sitem); if (inven_check_num(&sell_obj)) { if (s_ptr->store_inven[item_val].scost > 0) { price = s_ptr->store_inven[item_val].scost; choice = 0; } else choice = purchase_haggle(store_num, &price, &sell_obj); if (choice == 0) { if (py.misc.au >= price) { prt_comment1(); decrease_insults(store_num); py.misc.au -= price; item_new = inven_carry(&sell_obj); i = s_ptr->store_ctr; store_destroy(store_num, item_val, TRUE); objdes(tmp_str, &inventory[item_new], TRUE); (void) sprintf(out_val, "You have %s (%c)", tmp_str, item_new+'a'); prt(out_val, 0, 0); check_strength(); if (*cur_top >= s_ptr->store_ctr) { *cur_top = 0; display_inventory(store_num, *cur_top); } else { r_ptr = &s_ptr->store_inven[item_val]; if (i == s_ptr->store_ctr) { if (r_ptr->scost < 0) { r_ptr->scost = price; display_cost(store_num, item_val); } } else display_inventory(store_num, item_val); } store_prt_gold(); } else { if (increase_insults(store_num)) purchase = TRUE; else { prt_comment1(); msg_print("Liar! You have not the gold!"); } } } else if (choice == 2) purchase = TRUE; /* Less intuitive, but looks better here than in purchase_haggle. */ display_commands(); erase_line (1, 0); } else prt("You cannot carry that many different items.", 0, 0); } return(purchase); } /* Sell an item to the store -RAK- */ static int store_sell(store_num, cur_top) int store_num, *cur_top; { int item_val, item_pos; int32 price; bigvtype out_val, tmp_str; inven_type sold_obj; register int sell, choice, flag; char mask[INVEN_WIELD]; int counter, first_item, last_item; sell = FALSE; first_item = inven_ctr; last_item = -1; for (counter = 0; counter < inven_ctr; counter++) { #ifdef MAC flag = store_buy(store_num, (inventory[counter].tval)); #else flag = (*store_buy[store_num])(inventory[counter].tval); #endif mask[counter] = flag; if (flag) { if (counter < first_item) first_item = counter; if (counter > last_item) last_item = counter; } /* end of if (flag) */ } /* end of for (counter) */ if (last_item == -1) msg_print("You have nothing to sell to this store!"); else if (get_item(&item_val, "Which one? ", first_item, last_item, mask, "I do not buy such items.")) { take_one_item(&sold_obj, &inventory[item_val]); objdes(tmp_str, &sold_obj, TRUE); (void) sprintf(out_val, "Selling %s (%c)", tmp_str, item_val+'a'); msg_print(out_val); if (store_check_num(&sold_obj, store_num)) { choice = sell_haggle(store_num, &price, &sold_obj); if (choice == 0) { prt_comment1(); decrease_insults(store_num); py.misc.au += price; /* identify object in inventory to set object_ident */ identify(&item_val); /* retake sold_obj so that it will be identified */ take_one_item(&sold_obj, &inventory[item_val]); /* call known2 for store item, so charges/pluses are known */ known2(&sold_obj); inven_destroy(item_val); objdes(tmp_str, &sold_obj, TRUE); (void) sprintf(out_val, "You've sold %s", tmp_str); msg_print(out_val); store_carry(store_num, &item_pos, &sold_obj); check_strength(); if (item_pos >= 0) { if (item_pos < 12) if (*cur_top < 12) display_inventory(store_num, item_pos); else { *cur_top = 0; display_inventory(store_num, *cur_top); } else if (*cur_top > 11) display_inventory(store_num, item_pos); else { *cur_top = 12; display_inventory(store_num, *cur_top); } } store_prt_gold(); } else if (choice == 2) sell = TRUE; else if (choice == 3) { msg_print("How dare you!"); msg_print("I will not buy that!"); sell = increase_insults(store_num); } /* Less intuitive, but looks better here than in sell_haggle. */ erase_line (1, 0); display_commands(); } else msg_print("I have not the room in my store to keep it."); } return(sell); } /* Entering a store -RAK- */ void enter_store(store_num) int store_num; { int cur_top, tmp_chr; char command; register int exit_flag; register store_type *s_ptr; s_ptr = &store[store_num]; if (s_ptr->store_open < turn) { exit_flag = FALSE; cur_top = 0; display_store(store_num, cur_top); do { move_cursor (20, 9); /* clear the msg flag just like we do in dungeon.c */ msg_flag = FALSE; if (get_com(CNIL, &command)) { switch(command) { case 'b': if (cur_top == 0) if (s_ptr->store_ctr > 12) { cur_top = 12; display_inventory(store_num, cur_top); } else msg_print("Entire inventory is shown."); else { cur_top = 0; display_inventory(store_num, cur_top); } break; case 'E': case 'e': /* Equipment List */ case 'I': case 'i': /* Inventory */ case 'T': case 't': /* Take off */ case 'W': case 'w': /* Wear */ case 'X': case 'x': /* Switch weapon */ tmp_chr = py.stats.use_stat[A_CHR]; do { inven_command(command); command = doing_inven; } while (command); /* redisplay store prices if charisma changes */ if (tmp_chr != py.stats.use_stat[A_CHR]) display_inventory(store_num, cur_top); free_turn_flag = FALSE; /* No free moves here. -CJS- */ break; case 'p': exit_flag = store_purchase(store_num, &cur_top); break; case 's': exit_flag = store_sell(store_num, &cur_top); break; default: bell(); break; } } else exit_flag = TRUE; } while (!exit_flag); /* Can't save and restore the screen because inven_command does that. */ draw_cave(); } else msg_print("The doors are locked."); } moria-5.6.debian.1/source/help.c0000644000175000017500000001541511074756544014602 0ustar pjbpjb/* source/help.c: identify a symbol Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" void ident_char() { char command, query; register int i, n; if (get_com("Enter character to be identified :", &command)) switch(command) { /* every printing ASCII character is listed here, in the order in which they appear in the ASCII character set */ case ' ': prt(" - An open pit.", 0, 0); break; case '!': prt("! - A potion.", 0, 0); break; case '"': prt("\" - An amulet, periapt, or necklace.", 0, 0); break; case '#': prt("# - A stone wall.", 0, 0); break; case '$': prt("$ - Treasure.", 0, 0); break; case '%': if (highlight_seams == TRUE) prt("% - A magma or quartz vein.", 0, 0); else prt("% - Not used.", 0, 0); break; case '&': prt("& - Treasure chest.", 0, 0); break; case '\'': prt("' - An open door.", 0, 0); break; case '(': prt("( - Soft armor.", 0, 0); break; case ')': prt(") - A shield.", 0, 0); break; case '*': prt("* - Gems.", 0, 0); break; case '+': prt("+ - A closed door.", 0, 0); break; case ',': prt(", - Food or mushroom patch.", 0, 0); break; case '-': prt("- - A wand", 0, 0); break; case '.': prt(". - Floor.", 0, 0); break; case '/': prt("/ - A pole weapon.", 0, 0); break; /* case '0': prt("0 - Not used.", 0, 0); break; */ case '1': prt("1 - Entrance to General Store.", 0, 0); break; case '2': prt("2 - Entrance to Armory.", 0, 0); break; case '3': prt("3 - Entrance to Weaponsmith.", 0, 0); break; case '4': prt("4 - Entrance to Temple.", 0, 0); break; case '5': prt("5 - Entrance to Alchemy shop.", 0, 0); break; case '6': prt("6 - Entrance to Magic-Users store.", 0, 0); break; /* case '7': prt("7 - Not used.", 0, 0); break; */ /* case '8': prt("8 - Not used.", 0, 0); break; */ /* case '9': prt("9 - Not used.", 0, 0); break;*/ case ':': prt(": - Rubble.", 0, 0); break; case ';': prt("; - A loose rock.", 0, 0); break; case '<': prt("< - An up staircase.", 0, 0); break; case '=': prt("= - A ring.", 0, 0); break; case '>': prt("> - A down staircase.", 0, 0); break; case '?': prt("? - A scroll.", 0, 0); break; case '@': prt(py.misc.name, 0, 0); break; case 'A': prt("A - Giant Ant Lion.", 0, 0); break; case 'B': prt("B - The Balrog.", 0, 0); break; case 'C': prt("C - Gelatinous Cube.", 0, 0); break; case 'D': prt("D - An Ancient Dragon (Beware).", 0, 0); break; case 'E': prt("E - Elemental.", 0, 0); break; case 'F': prt("F - Giant Fly.", 0, 0); break; case 'G': prt("G - Ghost.", 0, 0); break; case 'H': prt("H - Hobgoblin.", 0, 0); break; /* case 'I': prt("I - Invisible Stalker.", 0, 0); break; */ case 'J': prt("J - Jelly.", 0, 0); break; case 'K': prt("K - Killer Beetle.", 0, 0); break; case 'L': prt("L - Lich.", 0, 0); break; case 'M': prt("M - Mummy.", 0, 0); break; /* case 'N': prt("N - Not used.", 0, 0); break; */ case 'O': prt("O - Ooze.", 0, 0); break; case 'P': prt("P - Giant humanoid.", 0, 0); break; case 'Q': prt("Q - Quylthulg (Pulsing Flesh Mound).", 0, 0); break; case 'R': prt("R - Reptile.", 0, 0); break; case 'S': prt("S - Giant Scorpion.", 0, 0); break; case 'T': prt("T - Troll.", 0, 0); break; case 'U': prt("U - Umber Hulk.", 0, 0); break; case 'V': prt("V - Vampire.", 0, 0); break; case 'W': prt("W - Wight or Wraith.", 0, 0); break; case 'X': prt("X - Xorn.", 0, 0); break; case 'Y': prt("Y - Yeti.", 0, 0); break; /* case 'Z': prt("Z - Not used.", 0, 0); break; */ case '[': prt("[ - Hard armor.", 0, 0); break; case '\\': prt("\\ - A hafted weapon.", 0, 0); break; case ']': prt("] - Misc. armor.", 0, 0); break; case '^': prt("^ - A trap.", 0, 0); break; case '_': prt("_ - A staff.", 0, 0); break; /* case '`': prt("` - Not used.", 0, 0); break; */ case 'a': prt("a - Giant Ant.", 0, 0); break; case 'b': prt("b - Giant Bat.", 0, 0); break; case 'c': prt("c - Giant Centipede.", 0, 0); break; case 'd': prt("d - Dragon.", 0, 0); break; case 'e': prt("e - Floating Eye.", 0, 0); break; case 'f': prt("f - Giant Frog.", 0, 0); break; case 'g': prt("g - Golem.", 0, 0); break; case 'h': prt("h - Harpy.", 0, 0); break; case 'i': prt("i - Icky Thing.", 0, 0); break; case 'j': prt("j - Jackal.", 0, 0); break; case 'k': prt("k - Kobold.", 0, 0); break; case 'l': prt("l - Giant Louse.", 0, 0); break; case 'm': prt("m - Mold.", 0, 0); break; case 'n': prt("n - Naga.", 0, 0); break; case 'o': prt("o - Orc or Ogre.", 0, 0); break; case 'p': prt("p - Person (Humanoid).", 0, 0); break; case 'q': prt("q - Quasit.", 0, 0); break; case 'r': prt("r - Rodent.", 0, 0); break; case 's': prt("s - Skeleton.", 0, 0); break; case 't': prt("t - Giant Tick.", 0, 0); break; /* case 'u': prt("u - Not used.", 0, 0); break; */ /* case 'v': prt("v - Not used.", 0, 0); break; */ case 'w': prt("w - Worm or Worm Mass.", 0, 0); break; /* case 'x': prt("x - Not used.", 0, 0); break; */ case 'y': prt("y - Yeek.", 0, 0); break; case 'z': prt("z - Zombie.", 0, 0); break; case '{': prt("{ - Arrow, bolt, or bullet.", 0, 0); break; case '|': prt("| - A sword or dagger.", 0, 0); break; case '}': prt("} - Bow, crossbow, or sling.", 0, 0); break; case '~': prt("~ - Miscellaneous item.", 0, 0); break; default: prt("Not Used.", 0, 0); break; } /* Allow access to monster memory. -CJS- */ n = 0; for (i = MAX_CREATURES-1; i >= 0; i--) if ((c_list[i].cchar == command) && bool_roff_recall (i)) { if (n == 0) { put_buffer ("You recall those details? [y/n]", 0, 40); query = inkey(); if (query != 'y' && query != 'Y') break; erase_line (0, 40); save_screen (); } n++; query = roff_recall (i); restore_screen (); if (query == ESCAPE) break; } } moria-5.6.debian.1/source/main.c0000644000175000017500000003072511074756544014577 0ustar pjbpjb/* UNIX Moria Version 5.x source/main.c: initialization, main() function and main loop Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ /* Original copyright message follows; included for historical reasons but no longer valid. */ /* Moria Version 4.8 COPYRIGHT (c) Robert Alan Koeneke */ /* */ /* I lovingly dedicate this game to hackers and adventurers */ /* everywhere... */ /* */ /* */ /* Designer and Programmer : Robert Alan Koeneke */ /* University of Oklahoma */ /* */ /* Assistant Programmers : Jimmey Wayne Todd */ /* University of Oklahoma */ /* */ /* Gary D. McAdoo */ /* University of Oklahoma */ /* */ /* UNIX Port : James E. Wilson */ /* UC Berkeley */ /* wilson@kithrup.com */ /* */ /* MSDOS Port : Don Kneller */ /* 1349 - 10th ave */ /* San Francisco, CA 94122 */ /* kneller@cgl.ucsf.EDU */ /* ...ucbvax!ucsfcgl!kneller */ /* kneller@ucsf-cgl.BITNET */ /* */ /* BRUCE Moria : Christopher Stuart */ /* Monash University */ /* Melbourne, Victoria, AUSTRALIA */ /* cjs@moncsbruce.oz */ /* */ /* Amiga Port : Corey Gehman */ /* Clemson University */ /* cg377170@eng.clemson.edu */ /* */ /* Version 5.6 : David Grabiner */ /* grabiner@alumni.princeton.edu */ /* */ #ifdef __TURBOC__ #include #endif /* __TURBOC__ */ #include #include #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #ifndef USG #include #include #endif #ifdef USG #ifndef ATARIST_MWC #include #else #include "string.h" #endif #else #include #endif #include #ifdef Pyramid #include #else #include #endif #ifndef VMS #ifndef MAC #ifndef GEMDOS #ifndef AMIGA long time(); #endif #endif char *getenv(); #endif #endif #ifndef MAC #ifndef AMIGA #ifdef USG #if !defined(MSDOS) && !defined(ATARIST_TC) unsigned short getuid(), getgid(); #endif #else #ifndef SECURE #ifdef BSD4_3 uid_t getuid(), getgid(); #else /* other BSD versions */ int getuid(), getgid(); #endif #endif #endif #endif #endif #ifndef VMS #ifndef MAC #if defined(ultrix) || defined(USG) void perror(); #endif #endif #endif #ifndef VMS #ifndef MAC #ifdef USG void exit(); #endif #endif #endif /* #if defined(atarist) && defined(__GNUC__) long _stksize = 64*1024; #endif */ #ifdef ATARIST_MWC long _stksize = 18000; /*(SAJ) for MWC */ #endif #ifdef __TURBOC__ unsigned _stklen = 0x3fff; /* increase stack from 4K to 16K */ #endif #ifdef AMIGA \/* detach from cli process */ #ifdef LATTICE #define NEAR near #else #define NEAR #endif long NEAR _stack = 30000; long NEAR _priority = 0; long NEAR _BackGroundIO = 1; char * NEAR _procname = "Moria"; #endif #if defined(LINT_ARGS) static void char_inven_init(void); static void init_m_level(void); static void init_t_level(void); #if (COST_ADJ != 100) static void price_adjust(void); #endif #else static void char_inven_init(); static void init_m_level(); static void init_t_level(); #if (COST_ADJ != 100) static void price_adjust(); #endif #endif /* Initialize, restore, and get the ball rolling. -RAK- */ #ifdef MAC /* This is just a subroutine for the Mac version */ /* only options passed in are -orn */ /* save file name is never passed */ int moria_main(argc, argv) int argc; char *argv[]; #else int main(argc, argv) int argc; char *argv[]; #endif { int32u seed; int generate; int result; #ifndef MAC char *p; #endif int new_game = FALSE; int force_rogue_like = FALSE; int force_keys_to; /* default command set defined in config.h file */ rogue_like_commands = ROGUE_LIKE; #ifdef SECURE Authenticate(); #endif #ifdef MSDOS msdos_init(); /* find out where everything is */ #endif /* call this routine to grab a file pointer to the highscore file */ /* and prepare things to relinquish setuid privileges */ init_scorefile(); #ifndef SECURE #if !defined(MSDOS) && !defined(ATARIST_MWC) && !defined(MAC) #if !defined(AMIGA) && !defined(ATARIST_TC) #if !defined(atarist) if (0 != setuid(getuid())) { perror("Can't set permissions correctly! Setuid call failed.\n"); exit(0); } if (0 != setgid(getgid())) { perror("Can't set permissions correctly! Setgid call failed.\n"); exit(0); } #endif #endif #endif #endif /* use curses */ init_curses(); #ifdef VMS /* Bizarre, but yes this really is needed to make moria work correctly under VMS. */ restore_screen (); #endif /* catch those nasty signals */ /* must come after init_curses as some of the signal handlers use curses */ init_signals(); seed = 0; /* let wizard specify rng seed */ /* check for user interface option */ for (--argc, ++argv; argc > 0 && argv[0][0] == '-'; --argc, ++argv) switch (argv[0][1]) { case 'N': case 'n': new_game = TRUE; break; case 'O': case 'o': /* rogue_like_commands may be set in get_char(), so delay this until after read savefile if any */ force_rogue_like = TRUE; force_keys_to = FALSE; break; case 'R': case 'r': force_rogue_like = TRUE; force_keys_to = TRUE; break; #ifndef MAC case 'S': display_scores(TRUE); exit_game(); case 's': display_scores(FALSE); exit_game(); case 'W': case 'w': to_be_wizard = TRUE; if (isdigit((int)argv[0][2])) seed = atoi(&argv[0][2]); break; default: (void) printf("Usage: moria [-norsw] [savefile]\n"); exit_game(); #endif } #ifndef MAC /* Check operating hours */ /* If not wizard No_Control_Y */ read_times(); #endif /* Some necessary initializations */ /* all made into constants or initialized in variables.c */ #if (COST_ADJ != 100) price_adjust(); #endif /* Grab a random seed from the clock */ init_seeds(seed); /* Init monster and treasure levels for allocate */ init_m_level(); init_t_level(); /* Init the store inventories */ store_init(); #ifndef MAC /* On Mac, if -n is passed, no savefile is used */ /* If -n is not passed, the calling routine will know savefile name, hence, this code is not necessary */ /* Auto-restart of saved file */ if (argv[0] != CNIL) (void) strcpy (savefile, argv[0]); else if ((p = getenv("MORIA_SAV")) != CNIL) (void) strcpy(savefile, p); else if ((p = getenv("HOME")) != CNIL) #if defined(ATARIST_MWC) || defined(ATARIST_TC) (void) sprintf(savefile, "%s\\%s", p, MORIA_SAV); #else #ifdef VMS (void) sprintf(savefile, "%s%s", p, MORIA_SAV); #else (void) sprintf(savefile, "%s/%s", p, MORIA_SAV); #endif #endif else (void) strcpy(savefile, MORIA_SAV); #endif /* This restoration of a saved character may get ONLY the monster memory. In this case, get_char returns false. It may also resurrect a dead character (if you are the wizard). In this case, it returns true, but also sets the parameter "generate" to true, as it does not recover any cave details. */ result = FALSE; #ifdef MAC if ((new_game == FALSE) && get_char(&generate)) #else if ((new_game == FALSE) && !access(savefile, 0) && get_char(&generate)) #endif result = TRUE; /* enter wizard mode before showing the character display, but must wait until after get_char in case it was just a resurrection */ if (to_be_wizard) if (!enter_wiz_mode()) exit_game(); if (result) { change_name(); /* could be restoring a dead character after a signal or HANGUP */ if (py.misc.chp < 0) death = TRUE; } else { /* Create character */ create_character(); #ifdef MAC birth_date = time ((time_t *)0); #else birth_date = time ((long *)0); #endif char_inven_init(); py.flags.food = 7500; py.flags.food_digested = 2; if (class[py.misc.pclass].spell == MAGE) { /* Magic realm */ clear_screen(); /* makes spell list easier to read */ calc_spells(A_INT); calc_mana(A_INT); } else if (class[py.misc.pclass].spell == PRIEST) { /* Clerical realm*/ calc_spells(A_WIS); clear_screen(); /* force out the 'learn prayer' message */ calc_mana(A_WIS); } /* prevent ^c quit from entering score into scoreboard, and prevent signal from creating panic save until this point, all info needed for save file is now valid */ character_generated = 1; generate = TRUE; } if (force_rogue_like) rogue_like_commands = force_keys_to; magic_init(); /* Begin the game */ clear_screen(); prt_stat_block(); if (generate) generate_cave(); /* Loop till dead, or exit */ while(!death) { dungeon(); /* Dungeon logic */ #ifndef MAC /* check for eof here, see inkey() in io.c */ /* eof can occur if the process gets a HANGUP signal */ if (eof_flag) { (void) strcpy(died_from, "(end of input: saved)"); if (!save_char()) { (void) strcpy(died_from, "unexpected eof"); } /* should not reach here, by if we do, this guarantees exit */ death = TRUE; } #endif if (!death) generate_cave(); /* New level */ } exit_game(); /* Character gets buried. */ /* should never reach here, but just in case */ return (0); } /* Init players with some belongings -RAK- */ static void char_inven_init() { register int i, j; inven_type inven_init; /* this is needed for bash to work right, it can't hurt anyway */ for (i = 0; i < INVEN_ARRAY_SIZE; i++) invcopy(&inventory[i], OBJ_NOTHING); for (i = 0; i < 5; i++) { j = player_init[py.misc.pclass][i]; invcopy(&inven_init, j); /* this makes it known2 and known1 */ store_bought(&inven_init); /* must set this bit to display tohit/todam for stiletto */ if (inven_init.tval == TV_SWORD) inven_init.ident |= ID_SHOW_HITDAM; (void) inven_carry(&inven_init); } /* wierd place for it, but why not? */ for (i = 0; i < 32; i++) spell_order[i] = 99; } /* Initializes M_LEVEL array for use with PLACE_MONSTER -RAK- */ static void init_m_level() { register int i, k; for (i = 0; i <= MAX_MONS_LEVEL; i++) m_level[i] = 0; k = MAX_CREATURES - WIN_MON_TOT; for (i = 0; i < k; i++) m_level[c_list[i].level]++; for (i = 1; i <= MAX_MONS_LEVEL; i++) #if defined(AMIGA) && !defined(LATTICE) /* fix a stupid MANX Aztec C 5.0 bug again */ m_level[i] = m_level[i] + m_level[i-1]; #else m_level[i] += m_level[i-1]; #endif } /* Initializes T_LEVEL array for use with PLACE_OBJECT -RAK- */ static void init_t_level() { register int i, l; int tmp[MAX_OBJ_LEVEL+1]; for (i = 0; i <= MAX_OBJ_LEVEL; i++) t_level[i] = 0; for (i = 0; i < MAX_DUNGEON_OBJ; i++) t_level[object_list[i].level]++; for (i = 1; i <= MAX_OBJ_LEVEL; i++) #if defined(AMIGA) && !defined(LATTICE) /* fix a stupid MANX Aztec C 5.0 bug again */ t_level[i] = t_level[i] + t_level[i-1]; #else t_level[i] += t_level[i-1]; #endif /* now produce an array with object indexes sorted by level, by using the info in t_level, this is an O(n) sort! */ /* this is not a stable sort, but that does not matter */ for (i = 0; i <= MAX_OBJ_LEVEL; i++) tmp[i] = 1; for (i = 0; i < MAX_DUNGEON_OBJ; i++) { l = object_list[i].level; sorted_objects[t_level[l] - tmp[l]] = i; tmp[l]++; } } #if (COST_ADJ != 100) /* Adjust prices of objects -RAK- */ static void price_adjust() { register int i; /* round half-way cases up */ for (i = 0; i < MAX_OBJECTS; i++) object_list[i].cost = ((object_list[i].cost * COST_ADJ) + 50) / 100; } #endif moria-5.6.debian.1/source/moria1.c0000644000175000017500000013421711074756544015044 0ustar pjbpjb/* source/moria1.c: misc code, mainly handles player movement, inventory, etc Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include #include #include #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #ifdef USG #ifndef ATARIST_MWC #include #else char *strcat(); int strlen(); #endif #else #include #endif #if defined(LINT_ARGS) static void inven_screen(int); static char map_roguedir(char); static void sub1_move_light(int, int, int, int); static void sub3_move_light(int, int, int, int); #endif #ifdef ATARIST_TC /* Include this to get prototypes for standard library functions. */ #include #endif /* Changes speed of monsters relative to player -RAK- */ /* Note: When the player is sped up or slowed down, I simply */ /* change the speed of all the monsters. This greatly */ /* simplified the logic. */ void change_speed(num) register int num; { register int i; #ifdef ATARIST_MWC int32u holder; #endif py.flags.speed += num; #ifdef ATARIST_MWC py.flags.status |= (holder = PY_SPEED); #else py.flags.status |= PY_SPEED; #endif for (i = mfptr - 1; i >= MIN_MONIX; i--) m_list[i].cspeed += num; } /* Player bonuses -RAK- */ /* When an item is worn or taken off, this re-adjusts the player */ /* bonuses. Factor=1 : wear; Factor=-1 : removed */ /* Only calculates properties with cumulative effect. Properties that depend on everything being worn are recalculated by calc_bonuses() -CJS- */ void py_bonuses(t_ptr, factor) register inven_type *t_ptr; register int factor; { register int i, amount; #ifdef ATARIST_MWC int32u holder; #endif amount = t_ptr->p1 * factor; if (t_ptr->flags & TR_STATS) { for(i = 0; i < 6; i++) if ((1 << i) & t_ptr->flags) bst_stat(i, amount); } if (TR_SEARCH & t_ptr->flags) { py.misc.srh += amount; py.misc.fos -= amount; } if (TR_STEALTH & t_ptr->flags) py.misc.stl += amount; if (TR_SPEED & t_ptr->flags) change_speed(-amount); #ifdef ATARIST_MWC if (((holder = TR_BLIND) & t_ptr->flags) && (factor > 0)) py.flags.blind += 1000; if (((holder = TR_TIMID) & t_ptr->flags) && (factor > 0)) py.flags.afraid += 50; if ((holder = TR_INFRA) & t_ptr->flags) py.flags.see_infra += amount; #else if ((TR_BLIND & t_ptr->flags) && (factor > 0)) py.flags.blind += 1000; if ((TR_TIMID & t_ptr->flags) && (factor > 0)) py.flags.afraid += 50; if (TR_INFRA & t_ptr->flags) py.flags.see_infra += amount; #endif } /* Recalculate the effect of all the stuff we use. -CJS- */ void calc_bonuses() { register int32u item_flags; #if defined(ATARIST_MWC) int32u holder; /* to avoid a compiler bug */ #endif int old_dis_ac; register struct flags *p_ptr; register struct misc *m_ptr; register inven_type *i_ptr; register int i; p_ptr = &py.flags; m_ptr = &py.misc; if (p_ptr->slow_digest) p_ptr->food_digested++; if (p_ptr->regenerate) p_ptr->food_digested -= 3; p_ptr->see_inv = FALSE; p_ptr->teleport = FALSE; p_ptr->free_act = FALSE; p_ptr->slow_digest = FALSE; p_ptr->aggravate = FALSE; p_ptr->sustain_str = FALSE; p_ptr->sustain_int = FALSE; p_ptr->sustain_wis = FALSE; p_ptr->sustain_con = FALSE; p_ptr->sustain_dex = FALSE; p_ptr->sustain_chr = FALSE; p_ptr->fire_resist = FALSE; p_ptr->acid_resist = FALSE; p_ptr->cold_resist = FALSE; p_ptr->regenerate = FALSE; p_ptr->lght_resist = FALSE; p_ptr->ffall = FALSE; old_dis_ac = m_ptr->dis_ac; m_ptr->ptohit = tohit_adj(); /* Real To Hit */ m_ptr->ptodam = todam_adj(); /* Real To Dam */ m_ptr->ptoac = toac_adj(); /* Real To AC */ m_ptr->pac = 0; /* Real AC */ m_ptr->dis_th = m_ptr->ptohit; /* Display To Hit */ m_ptr->dis_td = m_ptr->ptodam; /* Display To Dam */ m_ptr->dis_ac = 0; /* Display AC */ m_ptr->dis_tac = m_ptr->ptoac; /* Display To AC */ for (i = INVEN_WIELD; i < INVEN_LIGHT; i++) { i_ptr = &inventory[i]; if (i_ptr->tval != TV_NOTHING) { m_ptr->ptohit += i_ptr->tohit; if (i_ptr->tval != TV_BOW) /* Bows can't damage. -CJS- */ m_ptr->ptodam += i_ptr->todam; m_ptr->ptoac += i_ptr->toac; m_ptr->pac += i_ptr->ac; if (known2_p(i_ptr)) { m_ptr->dis_th += i_ptr->tohit; if (i_ptr->tval != TV_BOW) m_ptr->dis_td += i_ptr->todam; /* Bows can't damage. -CJS- */ m_ptr->dis_tac += i_ptr->toac; m_ptr->dis_ac += i_ptr->ac; } else if (! (TR_CURSED & i_ptr->flags)) /* Base AC values should always be visible, as long as the item is not cursed. */ m_ptr->dis_ac += i_ptr->ac; } } m_ptr->dis_ac += m_ptr->dis_tac; if (weapon_heavy) m_ptr->dis_th += (py.stats.use_stat[A_STR] * 15 - inventory[INVEN_WIELD].weight); /* Add in temporary spell increases */ if (p_ptr->invuln > 0) { m_ptr->pac += 100; m_ptr->dis_ac += 100; } if (p_ptr->blessed > 0) { m_ptr->pac += 2; m_ptr->dis_ac += 2; } if (p_ptr->detect_inv > 0) p_ptr->see_inv = TRUE; /* can't print AC here because might be in a store */ if (old_dis_ac != m_ptr->dis_ac) #ifdef ATARIST_MWC p_ptr->status |= (holder = PY_ARMOR); #else p_ptr->status |= PY_ARMOR; #endif item_flags = 0; i_ptr = &inventory[INVEN_WIELD]; for (i = INVEN_WIELD; i < INVEN_LIGHT; i++) { item_flags |= i_ptr->flags; i_ptr++; } #if !defined(ATARIST_MWC) if (TR_SLOW_DIGEST & item_flags) p_ptr->slow_digest = TRUE; if (TR_AGGRAVATE & item_flags) p_ptr->aggravate = TRUE; if (TR_TELEPORT & item_flags) p_ptr->teleport = TRUE; if (TR_REGEN & item_flags) p_ptr->regenerate = TRUE; if (TR_RES_FIRE & item_flags) p_ptr->fire_resist = TRUE; if (TR_RES_ACID & item_flags) p_ptr->acid_resist = TRUE; if (TR_RES_COLD & item_flags) p_ptr->cold_resist = TRUE; if (TR_FREE_ACT & item_flags) p_ptr->free_act = TRUE; if (TR_SEE_INVIS & item_flags) p_ptr->see_inv = TRUE; if (TR_RES_LIGHT & item_flags) p_ptr->lght_resist = TRUE; if (TR_FFALL & item_flags) p_ptr->ffall = TRUE; #else /* this avoids a bug in the Mark Williams C compiler for the Atari ST */ holder = TR_SLOW_DIGEST; if (holder & item_flags) p_ptr->slow_digest = TRUE; holder = TR_AGGRAVATE; if (holder & item_flags) p_ptr->aggravate = TRUE; holder = TR_TELEPORT; if (holder & item_flags) p_ptr->teleport = TRUE; holder = TR_REGEN; if (holder & item_flags) p_ptr->regenerate = TRUE; holder = TR_RES_FIRE; if (holder & item_flags) p_ptr->fire_resist = TRUE; holder = TR_RES_ACID; if (holder & item_flags) p_ptr->acid_resist = TRUE; holder = TR_RES_COLD; if (holder & item_flags) p_ptr->cold_resist = TRUE; holder = TR_FREE_ACT; if (holder & item_flags) p_ptr->free_act = TRUE; holder = TR_SEE_INVIS; if (holder & item_flags) p_ptr->see_inv = TRUE; holder = TR_RES_LIGHT; if (holder & item_flags) p_ptr->lght_resist = TRUE; holder = TR_FFALL; if (holder & item_flags) p_ptr->ffall = TRUE; #endif i_ptr = &inventory[INVEN_WIELD]; for (i = INVEN_WIELD; i < INVEN_LIGHT; i++) { #ifdef ATARIST_MWC if ((holder = TR_SUST_STAT) & i_ptr->flags) #else if (TR_SUST_STAT & i_ptr->flags) #endif switch(i_ptr->p1) { case 1: p_ptr->sustain_str = TRUE; break; case 2: p_ptr->sustain_int = TRUE; break; case 3: p_ptr->sustain_wis = TRUE; break; case 4: p_ptr->sustain_con = TRUE; break; case 5: p_ptr->sustain_dex = TRUE; break; case 6: p_ptr->sustain_chr = TRUE; break; default: break; } i_ptr++; } if (p_ptr->slow_digest) p_ptr->food_digested--; if (p_ptr->regenerate) p_ptr->food_digested += 3; } /* Displays inventory items from r1 to r2 -RAK- */ /* Designed to keep the display as far to the right as possible. The -CJS- parameter col gives a column at which to start, but if the display does not fit, it may be moved left. The return value is the left edge used. */ /* If mask is non-zero, then only display those items which have a non-zero entry in the mask array. */ int show_inven(r1, r2, weight, col, mask) register int r1, r2; int weight, col; char *mask; { register int i; int total_weight, len, l, lim, current_line; bigvtype tmp_val; vtype out_val[23]; len = 79 - col; if (weight) lim = 68; else lim = 76; for (i = r1; i <= r2; i++) /* Print the items */ { if (mask == CNIL || mask[i]) { objdes(tmp_val, &inventory[i], TRUE); tmp_val[lim] = 0; /* Truncate if too long. */ (void) sprintf(out_val[i], "%c) %s", 'a'+i, tmp_val); l = strlen(out_val[i]) + 2; if (weight) l += 9; if (l > len) len = l; } } col = 79 - len; if (col < 0) col = 0; current_line = 1; for (i = r1; i <= r2; i++) { if (mask == CNIL || mask[i]) { /* don't need first two spaces if in first column */ if (col == 0) prt(out_val[i], current_line, col); else { put_buffer(" ", current_line, col); prt(out_val[i], current_line, col+2); } if (weight) { total_weight = inventory[i].weight*inventory[i].number; (void) sprintf (tmp_val, "%3d.%d lb", (total_weight) / 10, (total_weight) % 10); prt (tmp_val, current_line, 71); } current_line++; } } return col; } /* Return a string describing how a given equipment item is carried. -CJS- */ char *describe_use(i) register int i; { register char *p; switch(i) { case INVEN_WIELD: p = "wielding"; break; case INVEN_HEAD: p = "wearing on your head"; break; case INVEN_NECK: p = "wearing around your neck"; break; case INVEN_BODY: p = "wearing on your body"; break; case INVEN_ARM: p = "wearing on your arm"; break; case INVEN_HANDS: p = "wearing on your hands"; break; case INVEN_RIGHT: p = "wearing on your right hand"; break; case INVEN_LEFT: p = "wearing on your left hand"; break; case INVEN_FEET: p = "wearing on your feet"; break; case INVEN_OUTER: p = "wearing about your body"; break; case INVEN_LIGHT: p = "using to light the way"; break; case INVEN_AUX: p = "holding ready by your side"; break; default: p = "carrying in your pack"; break; } return p; } /* Displays equipment items from r1 to end -RAK- */ /* Keep display as far right as possible. -CJS- */ int show_equip(weight, col) int weight, col; { register int i, line; int total_weight, l, len, lim; register char *prt1; bigvtype prt2; vtype out_val[INVEN_ARRAY_SIZE-INVEN_WIELD]; register inven_type *i_ptr; line = 0; len = 79 - col; if (weight) lim = 52; else lim = 60; for (i = INVEN_WIELD; i < INVEN_ARRAY_SIZE; i++) /* Range of equipment */ { i_ptr = &inventory[i]; if (i_ptr->tval != TV_NOTHING) { switch(i) /* Get position */ { case INVEN_WIELD: if (py.stats.use_stat[A_STR]*15 < i_ptr->weight) prt1 = "Just lifting"; else prt1 = "Wielding"; break; case INVEN_HEAD: prt1 = "On head"; break; case INVEN_NECK: prt1 = "Around neck"; break; case INVEN_BODY: prt1 = "On body"; break; case INVEN_ARM: prt1 = "On arm"; break; case INVEN_HANDS: prt1 = "On hands"; break; case INVEN_RIGHT: prt1 = "On right hand"; break; case INVEN_LEFT: prt1 = "On left hand"; break; case INVEN_FEET: prt1 = "On feet"; break; case INVEN_OUTER: prt1 = "About body"; break; case INVEN_LIGHT: prt1 = "Light source"; break; case INVEN_AUX: prt1 = "Spare weapon"; break; default: prt1 = "Unknown value"; break; } objdes(prt2, &inventory[i], TRUE); prt2[lim] = 0; /* Truncate if necessary */ (void) sprintf(out_val[line], "%c) %-14s: %s", line+'a', prt1, prt2); l = strlen(out_val[line]) + 2; if (weight) l += 9; if (l > len) len = l; line++; } } col = 79 - len; if (col < 0) col = 0; line = 0; for (i = INVEN_WIELD; i < INVEN_ARRAY_SIZE; i++) /* Range of equipment */ { i_ptr = &inventory[i]; if (i_ptr->tval != TV_NOTHING) { /* don't need first two spaces when using whole screen */ if (col == 0) prt(out_val[line], line+1, col); else { put_buffer(" ", line+1, col); prt(out_val[line], line+1, col+2); } if (weight) { total_weight = i_ptr->weight*i_ptr->number; (void) sprintf(prt2, "%3d.%d lb", (total_weight) / 10, (total_weight) % 10); prt(prt2, line+1, 71); } line++; } } erase_line(line+1, col); return col; } /* Remove item from equipment list -RAK- */ void takeoff(item_val, posn) int item_val, posn; { register char *p; bigvtype out_val, prt2; register inven_type *t_ptr; #ifdef ATARIST_MWC int32u holder; #endif equip_ctr--; t_ptr = &inventory[item_val]; inven_weight -= t_ptr->weight*t_ptr->number; #ifdef ATARIST_MWC py.flags.status |= (holder = PY_STR_WGT); #else py.flags.status |= PY_STR_WGT; #endif if (item_val == INVEN_WIELD || item_val == INVEN_AUX) p = "Was wielding "; else if (item_val == INVEN_LIGHT) p = "Light source was "; else p = "Was wearing "; objdes(prt2, t_ptr, TRUE); if (posn >= 0) (void) sprintf(out_val, "%s%s (%c)", p, prt2, 'a'+posn); else (void) sprintf(out_val, "%s%s", p, prt2); msg_print(out_val); if (item_val != INVEN_AUX) /* For secondary weapon */ py_bonuses(t_ptr, -1); invcopy(t_ptr, OBJ_NOTHING); } /* Used to verify if this really is the item we wish to -CJS- wear or read. */ int verify(prompt, item) char *prompt; int item; { bigvtype out_str, object; objdes(object, &inventory[item], TRUE); object[strlen(object)-1] = '?'; /* change the period to a question mark */ (void) sprintf(out_str, "%s %s", prompt, object); return get_check(out_str); } /* All inventory commands (wear, exchange, take off, drop, inventory and equipment) are handled in an alternative command input mode, which accepts any of the inventory commands. It is intended that this function be called several times in succession, as some commands take up a turn, and the rest of moria must proceed in the interim. A global variable is provided, doing_inven, which is normally zero; however if on return from inven_command it is expected that inven_command should be called *again*, (being still in inventory command input mode), then doing_inven is set to the inventory command character which should be used in the next call to inven_command. On return, the screen is restored, but not flushed. Provided no flush of the screen takes place before the next call to inven_command, the inventory command screen is silently redisplayed, and no actual output takes place at all. If the screen is flushed before a subsequent call, then the player is prompted to see if we should continue. This allows the player to see any changes that take place on the screen during inventory command input. The global variable, screen_change, is cleared by inven_command, and set when the screen is flushed. This is the means by which inven_command tell if the screen has been flushed. The display of inventory items is kept to the right of the screen to minimize the work done to restore the screen afterwards. -CJS-*/ /* Inventory command screen states. */ #define BLANK_SCR 0 #define EQUIP_SCR 1 #define INVEN_SCR 2 #define WEAR_SCR 3 #define HELP_SCR 4 #define WRONG_SCR 5 /* Keep track of the state of the inventory screen. */ static int scr_state, scr_left, scr_base; static int wear_low, wear_high; /* Draw the inventory screen. */ static void inven_screen(new_scr) int new_scr; { register int line; if (new_scr != scr_state) { scr_state = new_scr; switch(new_scr) { case BLANK_SCR: line = 0; break; case HELP_SCR: if (scr_left > 52) scr_left = 52; prt(" ESC: exit", 1, scr_left); prt(" w : wear or wield object", 2, scr_left); prt(" t : take off item", 3, scr_left); prt(" d : drop object", 4, scr_left); prt(" x : exchange weapons", 5, scr_left); prt(" i : inventory of pack", 6, scr_left); prt(" e : list used equipment", 7, scr_left); line = 7; break; case INVEN_SCR: scr_left = show_inven(0, inven_ctr - 1, show_weight_flag, scr_left, CNIL); line = inven_ctr; break; case WEAR_SCR: scr_left = show_inven(wear_low, wear_high, show_weight_flag, scr_left, CNIL); line = wear_high - wear_low + 1; break; case EQUIP_SCR: scr_left = show_equip(show_weight_flag, scr_left); line = equip_ctr; break; } if (line >= scr_base) { scr_base = line + 1; erase_line(scr_base, scr_left); } else { while (++line <= scr_base) erase_line(line, scr_left); } } } /* This does all the work. */ void inven_command(command) char command; { register int slot, item; int tmp, tmp2, selecting, from, to; char *prompt, *swap, *disp, *string; char which, query; bigvtype prt1, prt2; register inven_type *i_ptr; inven_type tmp_obj; #ifdef ATARIST_MWC int32u holder; #endif free_turn_flag = TRUE; save_screen(); /* Take up where we left off after a previous inventory command. -CJS- */ if (doing_inven) { /* If the screen has been flushed, we need to redraw. If the command is a simple ' ' to recover the screen, just quit. Otherwise, check and see what the user wants. */ if (screen_change) { if (command == ' ' || !get_check("Continuing with inventory command?")) { doing_inven = FALSE; return; } scr_left = 50; scr_base = 0; } tmp = scr_state; scr_state = WRONG_SCR; inven_screen(tmp); } else { scr_left = 50; scr_base = 0; /* this forces exit of inven_command() if selecting is not set true */ scr_state = BLANK_SCR; } do { if (isupper((int)command)) command = tolower((int)command); /* Simple command getting and screen selection. */ selecting = FALSE; switch(command) { case 'i': /* Inventory */ if (inven_ctr == 0) msg_print("You are not carrying anything."); else inven_screen(INVEN_SCR); break; case 'e': /* Equipment */ if (equip_ctr == 0) msg_print("You are not using any equipment."); else inven_screen(EQUIP_SCR); break; case 't': /* Take off */ if (equip_ctr == 0) msg_print("You are not using any equipment."); /* don't print message restarting inven command after taking off something, it is confusing */ else if (inven_ctr >= INVEN_WIELD && !doing_inven) msg_print("You will have to drop something first."); else { if (scr_state != BLANK_SCR) inven_screen(EQUIP_SCR); selecting = TRUE; } break; case 'd': /* Drop */ if (inven_ctr == 0 && equip_ctr == 0) msg_print("But you're not carrying anything."); else if (cave[char_row][char_col].tptr != 0) msg_print("There's no room to drop anything here."); else { selecting = TRUE; if ((scr_state == EQUIP_SCR && equip_ctr > 0) || inven_ctr == 0) { if (scr_state != BLANK_SCR) inven_screen(EQUIP_SCR); command = 'r'; /* Remove - or take off and drop. */ } else if (scr_state != BLANK_SCR) inven_screen(INVEN_SCR); } break; case 'w': /* Wear/wield */ for (wear_low = 0; wear_low < inven_ctr && inventory[wear_low].tval > TV_MAX_WEAR; wear_low++) ; for(wear_high = wear_low; wear_high < inven_ctr && inventory[wear_high].tval >=TV_MIN_WEAR; wear_high++) ; wear_high--; if (wear_low > wear_high) msg_print("You have nothing to wear or wield."); else { if (scr_state != BLANK_SCR && scr_state != INVEN_SCR) inven_screen(WEAR_SCR); selecting = TRUE; } break; case 'x': if (inventory[INVEN_WIELD].tval == TV_NOTHING && inventory[INVEN_AUX].tval == TV_NOTHING) msg_print("But you are wielding no weapons."); #ifdef ATARIST_MWC else if ((holder = TR_CURSED) & inventory[INVEN_WIELD].flags) #else else if (TR_CURSED & inventory[INVEN_WIELD].flags) #endif { objdes(prt1, &inventory[INVEN_WIELD], FALSE); (void) sprintf(prt2, "The %s you are wielding appears to be cursed.", prt1); msg_print(prt2); } else { free_turn_flag = FALSE; tmp_obj = inventory[INVEN_AUX]; inventory[INVEN_AUX] = inventory[INVEN_WIELD]; inventory[INVEN_WIELD] = tmp_obj; if (scr_state == EQUIP_SCR) scr_left = show_equip(show_weight_flag, scr_left); py_bonuses(&inventory[INVEN_AUX], -1); /* Subtract bonuses */ py_bonuses(&inventory[INVEN_WIELD], 1); /* Add bonuses */ if (inventory[INVEN_WIELD].tval != TV_NOTHING) { (void) strcpy(prt1, "Primary weapon : "); objdes(prt2, &inventory[INVEN_WIELD], TRUE); msg_print(strcat(prt1, prt2)); } else msg_print("No primary weapon."); /* this is a new weapon, so clear the heavy flag */ weapon_heavy = FALSE; check_strength(); } break; case ' ': /* Dummy command to return again to main prompt. */ break; case '?': inven_screen(HELP_SCR); break; default: /* Nonsense command */ bell(); break; } /* Clear the doing_inven flag here, instead of at beginning, so that can use it to control when messages above appear. */ doing_inven = 0; /* Keep looking for objects to drop/wear/take off/throw off */ which = 'z'; while (selecting && free_turn_flag) { swap = ""; if (command == 'w') { from = wear_low; to = wear_high; prompt = "Wear/Wield"; } else { from = 0; if (command == 'd') { to = inven_ctr - 1; prompt = "Drop"; if (equip_ctr > 0) swap = ", / for Equip"; } else { to = equip_ctr - 1; if (command == 't') prompt = "Take off"; else /* command == 'r' */ { prompt = "Throw off"; if (inven_ctr > 0) swap = ", / for Inven"; } } } if (from > to) selecting = FALSE; else { if (scr_state == BLANK_SCR) disp = ", * to list"; else disp = ""; (void) sprintf(prt1, "(%c-%c%s%s%s, space to break, ESC to exit) %s which one?", from+'a', to+'a', disp, swap, ((command == 'w' || command == 'd') ? ", 0-9" : "") , prompt); /* Abort everything. */ if (!get_com(prt1, &which)) { selecting = FALSE; which = ESCAPE; } /* Draw the screen and maybe exit to main prompt. */ else if (which == ' ' || which == '*') { if (command == 't' || command == 'r') inven_screen(EQUIP_SCR); else if (command == 'w' && scr_state != INVEN_SCR) inven_screen(WEAR_SCR); else inven_screen(INVEN_SCR); if (which == ' ') selecting = FALSE; } /* Swap screens (for drop) */ else if (which == '/' && swap[0]) { if (command == 'd') command = 'r'; else command = 'd'; if (scr_state == EQUIP_SCR) inven_screen(INVEN_SCR); else if (scr_state == INVEN_SCR) inven_screen(EQUIP_SCR); } else { if ((which >= '0') && (which <= '9') && (command != 'r') && (command != 't')) { /* look for item whose inscription matches "which" */ register int m; for (m = from; m <= to && ((inventory[m].inscrip[0] != which) || (inventory[m].inscrip[1] != '\0')); m++); if (m <= to) item = m; else item = -1; } else if ((which >= 'A') && (which <= 'Z')) item = which - 'A'; else item = which - 'a'; if (item < from || item > to) bell(); else /* Found an item! */ { if (command == 'r' || command == 't') { /* Get its place in the equipment list. */ tmp = item; item = 21; do { item++; if (inventory[item].tval != TV_NOTHING) tmp--; } while (tmp >= 0); if (isupper((int)which) && !verify(prompt, item)) item = -1; #ifdef ATARIST_MWC else if ((holder = TR_CURSED) & inventory[item].flags) #else else if (TR_CURSED & inventory[item].flags) #endif { msg_print("Hmmm, it seems to be cursed."); item = -1; } else if (command == 't' && !inven_check_num(&inventory[item])) { if (cave[char_row][char_col].tptr != 0) { msg_print("You can't carry it."); item = -1; } else if (get_check("You can't carry it. Drop it?")) command = 'r'; else item = -1; } if (item >= 0) { if (command == 'r') { inven_drop(item, TRUE); /* As a safety measure, set the player's inven weight to 0, when the last object is dropped*/ if (inven_ctr == 0 && equip_ctr == 0) inven_weight = 0; } else { slot = inven_carry(&inventory[item]); takeoff(item, slot); } check_strength(); free_turn_flag = FALSE; if (command == 'r') selecting = FALSE; } } else if (command == 'w') { /* Wearing. Go to a bit of trouble over replacing existing equipment. */ if (isupper((int)which) && !verify(prompt, item)) item = -1; else switch(inventory[item].tval) { /* Slot for equipment */ case TV_SLING_AMMO: case TV_BOLT: case TV_ARROW: case TV_BOW: case TV_HAFTED: case TV_POLEARM: case TV_SWORD: case TV_DIGGING: case TV_SPIKE: slot = INVEN_WIELD; break; case TV_LIGHT: slot = INVEN_LIGHT; break; case TV_BOOTS: slot = INVEN_FEET; break; case TV_GLOVES: slot = INVEN_HANDS; break; case TV_CLOAK: slot = INVEN_OUTER; break; case TV_HELM: slot = INVEN_HEAD; break; case TV_SHIELD: slot = INVEN_ARM; break; case TV_HARD_ARMOR: case TV_SOFT_ARMOR: slot = INVEN_BODY; break; case TV_AMULET: slot = INVEN_NECK; break; case TV_RING: if (inventory[INVEN_RIGHT].tval == TV_NOTHING) slot = INVEN_RIGHT; else if (inventory[INVEN_LEFT].tval == TV_NOTHING) slot = INVEN_LEFT; else { slot = 0; /* Rings. Give choice over where they go. */ do { if (!get_com( "Put ring on which hand (l/r/L/R)?", &query)) { item = -1; slot = -1; } else if (query == 'l') slot = INVEN_LEFT; else if (query == 'r') slot = INVEN_RIGHT; else { if (query == 'L') slot = INVEN_LEFT; else if (query == 'R') slot = INVEN_RIGHT; else bell(); if (slot && !verify("Replace", slot)) slot = 0; } } while(slot == 0); } break; default: msg_print("IMPOSSIBLE: I don't see how you can use that."); item = -1; break; } if (item >= 0 && inventory[slot].tval != TV_NOTHING) { #ifdef ATARIST_MWC if ((holder = TR_CURSED) & inventory[slot].flags) #else if (TR_CURSED & inventory[slot].flags) #endif { objdes(prt1, &inventory[slot], FALSE); (void) sprintf(prt2, "The %s you are ", prt1); if (slot == INVEN_HEAD) (void) strcat(prt2, "wielding "); else (void) strcat(prt2, "wearing "); msg_print(strcat(prt2, "appears to be cursed.")); item = -1; } else if (inventory[item].subval == ITEM_GROUP_MIN && inventory[item].number > 1 && !inven_check_num(&inventory[slot])) { /* this can happen if try to wield a torch, and have more than one in inventory */ msg_print("You will have to drop something first."); item = -1; } } if (item >= 0) { /* OK. Wear it. */ free_turn_flag = FALSE; /* first remove new item from inventory */ tmp_obj = inventory[item]; i_ptr = &tmp_obj; wear_high--; /* Fix for torches */ if (i_ptr->number > 1 && i_ptr->subval <= ITEM_SINGLE_STACK_MAX) { i_ptr->number = 1; wear_high++; } inven_weight += i_ptr->weight*i_ptr->number; inven_destroy(item); /* Subtracts weight */ /* second, add old item to inv and remove from equipment list, if necessary */ i_ptr = &inventory[slot]; if (i_ptr->tval != TV_NOTHING) { tmp2 = inven_ctr; tmp = inven_carry(i_ptr); /* if item removed did not stack with anything in inventory, then increment wear_high */ if (inven_ctr != tmp2) wear_high++; takeoff(slot, tmp); } /* third, wear new item */ *i_ptr = tmp_obj; equip_ctr++; py_bonuses(i_ptr, 1); if (slot == INVEN_WIELD) string = "You are wielding"; else if (slot == INVEN_LIGHT) string = "Your light source is"; else string = "You are wearing"; objdes(prt2, i_ptr, TRUE); /* Get the right equipment letter. */ tmp = INVEN_WIELD; item = 0; while (tmp != slot) if (inventory[tmp++].tval != TV_NOTHING) item++; (void) sprintf(prt1, "%s %s (%c)", string, prt2, 'a'+item); msg_print(prt1); /* this is a new weapon, so clear heavy flag */ if (slot == INVEN_WIELD) weapon_heavy = FALSE; check_strength(); #ifdef ATARIST_MWC if (i_ptr->flags & (holder = TR_CURSED)) #else if (i_ptr->flags & TR_CURSED) #endif { msg_print("Oops! It feels deathly cold!"); add_inscribe(i_ptr, ID_DAMD); /* To force a cost of 0, even if unidentified. */ i_ptr->cost = -1; } } } else /* command == 'd' */ { if (inventory[item].number > 1) { objdes(prt1, &inventory[item], TRUE); prt1[strlen(prt1)-1] = '?'; (void) sprintf(prt2, "Drop all %s [y/n]", prt1); prt1[strlen(prt1)-1] = '.'; prt(prt2, 0, 0); query = inkey(); if (query != 'y' && query != 'n') { if (query != ESCAPE) bell(); erase_line(MSG_LINE, 0); item = -1; } } else if (isupper((int)which) && !verify(prompt, item)) item = -1; else query = 'y'; if (item >= 0) { free_turn_flag = FALSE; /* Player turn */ inven_drop(item, query == 'y'); check_strength(); } selecting = FALSE; /* As a safety measure, set the player's inven weight to 0, when the last object is dropped. */ if (inven_ctr == 0 && equip_ctr == 0) inven_weight = 0; } if (free_turn_flag == FALSE && scr_state == BLANK_SCR) selecting = FALSE; } } } } if (which == ESCAPE || scr_state == BLANK_SCR) command = ESCAPE; else if (!free_turn_flag) { /* Save state for recovery if they want to call us again next turn.*/ if (selecting) doing_inven = command; else doing_inven = ' '; /* A dummy command to recover screen. */ /* flush last message before clearing screen_change and exiting */ msg_print(CNIL); screen_change = FALSE;/* This lets us know if the world changes */ command = ESCAPE; } else { /* Put an appropriate header. */ if (scr_state == INVEN_SCR) { if (! show_weight_flag || inven_ctr == 0) (void) sprintf(prt1, "You are carrying %d.%d pounds. In your pack there is %s", inven_weight / 10, inven_weight % 10, (inven_ctr == 0 ? "nothing." : "-")); else (void) sprintf (prt1, "You are carrying %d.%d pounds. Your capacity is %d.%d pounds. %s", inven_weight / 10, inven_weight % 10, weight_limit () / 10, weight_limit () % 10, "In your pack is -"); prt(prt1, 0, 0); } else if (scr_state == WEAR_SCR) { if (wear_high < wear_low) prt("You have nothing you could wield.", 0, 0); else prt("You could wield -", 0, 0); } else if (scr_state == EQUIP_SCR) { if (equip_ctr == 0) prt("You are not using anything.", 0, 0); else prt("You are using -", 0, 0); } else prt("Allowed commands:", 0, 0); erase_line(scr_base, scr_left); put_buffer("e/i/t/w/x/d/?/ESC:", scr_base, 60); command = inkey(); erase_line(scr_base, scr_left); } } while (command != ESCAPE); if (scr_state != BLANK_SCR) restore_screen(); calc_bonuses(); } /* Get the ID of an item and return the CTR value of it -RAK- */ int get_item(com_val, pmt, i, j, mask, message) int *com_val; char *pmt; int i, j; char *mask; char *message; { vtype out_val; char which; register int test_flag, item; int full, i_scr, redraw; item = FALSE; redraw = FALSE; *com_val = 0; i_scr = 1; if (j > INVEN_WIELD) { full = TRUE; if (inven_ctr == 0) { i_scr = 0; j = equip_ctr - 1; } else j = inven_ctr - 1; } else full = FALSE; if (inven_ctr > 0 || (full && equip_ctr > 0)) { do { if (redraw) { if (i_scr > 0) (void) show_inven (i, j, FALSE, 80, mask); else (void) show_equip (FALSE, 80); } if (full) (void) sprintf(out_val, "(%s: %c-%c,%s%s / for %s, or ESC) %s", (i_scr > 0 ? "Inven" : "Equip"), i+'a', j+'a', (i_scr > 0 ? " 0-9," : ""), (redraw ? "" : " * to see,"), (i_scr > 0 ? "Equip" : "Inven"), pmt); else (void) sprintf(out_val, "(Items %c-%c,%s%s ESC to exit) %s", i+'a', j+'a', (i_scr > 0 ? " 0-9," : ""), (redraw ? "" : " * for inventory list,"), pmt); test_flag = FALSE; prt(out_val, 0, 0); do { which = inkey(); switch(which) { case ESCAPE: test_flag = TRUE; free_turn_flag = TRUE; i_scr = -1; break; case '/': if (full) { if (i_scr > 0) { if (equip_ctr == 0) { prt("But you're not using anything -more-",0,0); (void) inkey(); } else { i_scr = 0; test_flag = TRUE; if (redraw) { j = equip_ctr; while (j < inven_ctr) { j++; erase_line(j, 0); } } j = equip_ctr - 1; } prt(out_val, 0, 0); } else { if (inven_ctr == 0) { prt("But you're not carrying anything -more-",0,0); (void) inkey(); } else { i_scr = 1; test_flag = TRUE; if (redraw) { j = inven_ctr; while (j < equip_ctr) { j++; erase_line (j, 0); } } j = inven_ctr - 1; } } } break; case '*': if (!redraw) { test_flag = TRUE; save_screen(); redraw = TRUE; } break; default: if ((which >= '0') && (which <= '9') && (i_scr != 0)) /* look for item whose inscription matches "which" */ { register int m; for (m = i; (m < INVEN_WIELD) && ((inventory[m].inscrip[0] != which) || (inventory[m].inscrip[1] != '\0')); m++); if (m < INVEN_WIELD) *com_val = m; else *com_val = -1; } else if (isupper((int)which)) *com_val = which - 'A'; else *com_val = which - 'a'; if ((*com_val >= i) && (*com_val <= j) && (mask == CNIL || mask[*com_val])) { if (i_scr == 0) { i = 21; j = *com_val; do { while (inventory[++i].tval == TV_NOTHING); j--; } while (j >= 0); *com_val = i; } if (isupper((int)which) && !verify("Try", *com_val)) { test_flag = TRUE; free_turn_flag = TRUE; i_scr = -1; break; } test_flag = TRUE; item = TRUE; i_scr = -1; } else if (message) { msg_print (message); /* Set test_flag to force redraw of the question. */ test_flag = TRUE; } else bell(); break; } } while (!test_flag); } while (i_scr >= 0); if (redraw) restore_screen(); erase_line(MSG_LINE, 0); } else prt("You are not carrying anything.", 0, 0); return(item); } /* I may have written the town level code, but I'm not exactly */ /* proud of it. Adding the stores required some real slucky */ /* hooks which I have not had time to re-think. -RAK- */ /* Returns true if player has no light -RAK- */ int no_light() { register cave_type *c_ptr; c_ptr = &cave[char_row][char_col]; if (!c_ptr->tl && !c_ptr->pl) return TRUE; return FALSE; } /* map rogue_like direction commands into numbers */ static char map_roguedir(comval) register char comval; { switch(comval) { case 'h': comval = '4'; break; case 'y': comval = '7'; break; case 'k': comval = '8'; break; case 'u': comval = '9'; break; case 'l': comval = '6'; break; case 'n': comval = '3'; break; case 'j': comval = '2'; break; case 'b': comval = '1'; break; case '.': comval = '5'; break; } return(comval); } /* Prompts for a direction -RAK- */ /* Direction memory added, for repeated commands. -CJS */ int get_dir(prompt, dir) char *prompt; int *dir; { char command; int save; static char prev_dir; /* Direction memory. -CJS- */ if (default_dir) /* used in counted commands. -CJS- */ { *dir = prev_dir; return TRUE; } if (prompt == CNIL) prompt = "Which direction?"; for (;;) { save = command_count; /* Don't end a counted command. -CJS- */ #ifdef MAC if (!get_comdir(prompt, &command)) #else if (!get_com(prompt, &command)) #endif { free_turn_flag = TRUE; return FALSE; } command_count = save; if (rogue_like_commands) command = map_roguedir(command); if (command >= '1' && command <= '9' && command != '5') { prev_dir = command - '0'; *dir = prev_dir; return TRUE; } bell(); } } /* Similar to get_dir, except that no memory exists, and it is -CJS- allowed to enter the null direction. */ int get_alldir(prompt, dir) char *prompt; int *dir; { char command; for(;;) { #ifdef MAC if (!get_comdir(prompt, &command)) #else if (!get_com(prompt, &command)) #endif { free_turn_flag = TRUE; return FALSE; } if (rogue_like_commands) command = map_roguedir(command); if (command >= '1' && command <= '9') { *dir = command - '0'; return TRUE; } bell(); } } /* Moves creature record from one space to another -RAK- */ void move_rec(y1, x1, y2, x2) register int y1, x1, y2, x2; { int tmp; /* this always works correctly, even if y1==y2 and x1==x2 */ tmp = cave[y1][x1].cptr; cave[y1][x1].cptr = 0; cave[y2][x2].cptr = tmp; } /* Room is lit, make it appear -RAK- */ void light_room(y, x) int y, x; { register int i, j, start_col, end_col; int tmp1, tmp2, start_row, end_row; register cave_type *c_ptr; int tval; tmp1 = (SCREEN_HEIGHT/2); tmp2 = (SCREEN_WIDTH /2); start_row = (y/tmp1)*tmp1; start_col = (x/tmp2)*tmp2; end_row = start_row + tmp1 - 1; end_col = start_col + tmp2 - 1; for (i = start_row; i <= end_row; i++) for (j = start_col; j <= end_col; j++) { c_ptr = &cave[i][j]; if (c_ptr->lr && ! c_ptr->pl) { c_ptr->pl = TRUE; if (c_ptr->fval == DARK_FLOOR) c_ptr->fval = LIGHT_FLOOR; if (! c_ptr->fm && c_ptr->tptr != 0) { tval = t_list[c_ptr->tptr].tval; if (tval >= TV_MIN_VISIBLE && tval <= TV_MAX_VISIBLE) c_ptr->fm = TRUE; } print(loc_symbol(i, j), i, j); } } } /* Lights up given location -RAK- */ void lite_spot(y, x) register int y, x; { if (panel_contains(y, x)) print(loc_symbol(y, x), y, x); } /* Normal movement */ /* When FIND_FLAG, light only permanent features */ static void sub1_move_light(y1, x1, y2, x2) register int x1, x2; int y1, y2; { register int i, j; register cave_type *c_ptr; int tval, top, left, bottom, right; if (light_flag) { for (i = y1-1; i <= y1+1; i++) /* Turn off lamp light */ for (j = x1-1; j <= x1+1; j++) cave[i][j].tl = FALSE; if (find_flag && !find_prself) light_flag = FALSE; } else if (!find_flag || find_prself) light_flag = TRUE; for (i = y2-1; i <= y2+1; i++) for (j = x2-1; j <= x2+1; j++) { c_ptr = &cave[i][j]; /* only light up if normal movement */ if (light_flag) c_ptr->tl = TRUE; if (c_ptr->fval >= MIN_CAVE_WALL) c_ptr->pl = TRUE; else if (!c_ptr->fm && c_ptr->tptr != 0) { tval = t_list[c_ptr->tptr].tval; if ((tval >= TV_MIN_VISIBLE) && (tval <= TV_MAX_VISIBLE)) c_ptr->fm = TRUE; } } /* From uppermost to bottom most lines player was on. */ if (y1 < y2) { top = y1 - 1; bottom = y2 + 1; } else { top = y2 - 1; bottom = y1 + 1; } if (x1 < x2) { left = x1 - 1; right = x2 + 1; } else { left = x2 - 1; right = x1 + 1; } for (i = top; i <= bottom; i++) for (j = left; j <= right; j++) /* Leftmost to rightmost do*/ print(loc_symbol(i, j), i, j); } /* When blinded, move only the player symbol. */ /* With no light, movement becomes involved. */ static void sub3_move_light(y1, x1, y2, x2) register int y1, x1; int y2, x2; { register int i, j; if (light_flag) { for (i = y1-1; i <= y1+1; i++) for (j = x1-1; j <= x1+1; j++) { cave[i][j].tl = FALSE; print(loc_symbol(i, j), i, j); } light_flag = FALSE; } else if (!find_flag || find_prself) print(loc_symbol(y1, x1), y1, x1); if (!find_flag || find_prself) print('@', y2, x2); } /* Package for moving the character's light about the screen */ /* Four cases : Normal, Finding, Blind, and Nolight -RAK- */ void move_light(y1, x1, y2, x2) int y1, x1, y2, x2; { if (py.flags.blind > 0 || !player_light) sub3_move_light(y1, x1, y2, x2); else sub1_move_light(y1, x1, y2, x2); } /* Something happens to disturb the player. -CJS- The first arg indicates a major disturbance, which affects search. The second arg indicates a light change. */ void disturb(s, l) int s, l; { command_count = 0; if (s && (py.flags.status & PY_SEARCH)) search_off(); if (py.flags.rest != 0) rest_off(); if (l || find_flag) { find_flag = FALSE; check_view(); } flush(); } /* Search Mode enhancement -RAK- */ void search_on() { change_speed(1); py.flags.status |= PY_SEARCH; prt_state(); prt_speed(); py.flags.food_digested++; } void search_off() { #ifdef ATARIST_MWC int32u holder; #endif check_view(); change_speed(-1); #ifdef ATARIST_MWC py.flags.status &= ~(holder = PY_SEARCH); #else py.flags.status &= ~PY_SEARCH; #endif prt_state(); prt_speed(); py.flags.food_digested--; } /* Resting allows a player to safely restore his hp -RAK- */ void rest() { int rest_num; vtype rest_str; if (command_count > 0) { rest_num = command_count; command_count = 0; } else { prt("Rest for how long? ", 0, 0); rest_num = 0; if (get_string(rest_str, 0, 19, 5)) { if (rest_str[0] == '*') rest_num = -MAX_SHORT; else rest_num = atoi(rest_str); } } /* check for reasonable value, must be positive number in range of a short, or must be -MAX_SHORT */ if ((rest_num == -MAX_SHORT) || (rest_num > 0) && (rest_num < MAX_SHORT)) { if (py.flags.status & PY_SEARCH) search_off(); py.flags.rest = rest_num; py.flags.status |= PY_REST; prt_state(); py.flags.food_digested--; prt ("Press any key to stop resting...", 0, 0); put_qio(); } else { if (rest_num != 0) msg_print ("Invalid rest count."); erase_line(MSG_LINE, 0); free_turn_flag = TRUE; } } void rest_off() { #ifdef ATARIST_MWC int32u holder; #endif py.flags.rest = 0; #ifdef ATARIST_MWC py.flags.status &= ~(holder = PY_REST); #else py.flags.status &= ~PY_REST; #endif prt_state(); msg_print(CNIL); /* flush last message, or delete "press any key" message */ py.flags.food_digested++; } /* Attacker's level and plusses, defender's AC -RAK- */ int test_hit(bth, level, pth, ac, attack_type) int bth, level, pth, ac, attack_type; { register int i, die; disturb (1, 0); i = bth + pth * BTH_PLUS_ADJ + (level * class_level_adj[py.misc.pclass][attack_type]); /* pth could be less than 0 if player wielding weapon too heavy for him */ /* always miss 1 out of 20, always hit 1 out of 20 */ die = randint (20); if ((die != 1) && ((die == 20) || ((i > 0) && (randint (i) > ac)))) /* normal hit */ return TRUE; else return FALSE; } /* Decreases players hit points and sets death flag if necessary*/ /* -RAK- */ void take_hit(damage, hit_from) int damage; char *hit_from; { if (py.flags.invuln > 0) damage = 0; py.misc.chp -= damage; if (py.misc.chp < 0) { if (!death) { death = TRUE; (void) strcpy(died_from, hit_from); total_winner = FALSE; } new_level_flag = TRUE; } else prt_chp(); } moria-5.6.debian.1/source/scrolls.c0000644000175000017500000003411511074756544015331 0ustar pjbpjb/* source/scrolls.c: scroll code Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #ifdef USG #include #else #include #endif /* Scrolls for the reading -RAK- */ void read_scroll() { int32u i; int j, k, item_val, y, x; int tmp[6], flag, used_up; bigvtype out_val, tmp_str; register int ident, l; register inven_type *i_ptr; register struct misc *m_ptr; #ifdef ATARIST_MWC int32u holder = TR_CURSED; #endif free_turn_flag = TRUE; if (py.flags.blind > 0) msg_print("You can't see to read the scroll."); else if (no_light()) msg_print("You have no light to read by."); else if (py.flags.confused > 0) msg_print("You are too confused to read a scroll."); else if (inven_ctr == 0) msg_print("You are not carrying anything!"); else if (!find_range(TV_SCROLL1, TV_SCROLL2, &j, &k)) msg_print ("You are not carrying any scrolls!"); else if (get_item(&item_val, "Read which scroll?", j, k, CNIL, CNIL)) { i_ptr = &inventory[item_val]; free_turn_flag = FALSE; used_up = TRUE; i = i_ptr->flags; ident = FALSE; while (i != 0) { j = bit_pos(&i) + 1; if (i_ptr->tval == TV_SCROLL2) j += 32; /* Scrolls. */ switch(j) { case 1: i_ptr = &inventory[INVEN_WIELD]; if (i_ptr->tval != TV_NOTHING) { objdes(tmp_str, i_ptr, FALSE); (void) sprintf(out_val, "Your %s glows faintly!", tmp_str); msg_print(out_val); if (enchant(&i_ptr->tohit, 10)) { #ifdef ATARIST_MWC i_ptr->flags &= ~holder; #else i_ptr->flags &= ~TR_CURSED; #endif calc_bonuses(); } else msg_print("The enchantment fails."); ident = TRUE; } break; case 2: i_ptr = &inventory[INVEN_WIELD]; if (i_ptr->tval != TV_NOTHING) { objdes(tmp_str, i_ptr, FALSE); (void) sprintf(out_val, "Your %s glows faintly!", tmp_str); msg_print(out_val); if ((i_ptr->tval >= TV_HAFTED)&&(i_ptr->tval <= TV_DIGGING)) j = i_ptr->damage[0] * i_ptr->damage[1]; else /* Bows' and arrows' enchantments should not be limited by their low base damages */ j = 10; if (enchant(&i_ptr->todam, j)) { #ifdef ATARIST_MWC i_ptr->flags &= ~holder; #else i_ptr->flags &= ~TR_CURSED; #endif calc_bonuses (); } else msg_print("The enchantment fails."); ident = TRUE; } break; case 3: k = 0; l = 0; if (inventory[INVEN_BODY].tval != TV_NOTHING) tmp[k++] = INVEN_BODY; if (inventory[INVEN_ARM].tval != TV_NOTHING) tmp[k++] = INVEN_ARM; if (inventory[INVEN_OUTER].tval != TV_NOTHING) tmp[k++] = INVEN_OUTER; if (inventory[INVEN_HANDS].tval != TV_NOTHING) tmp[k++] = INVEN_HANDS; if (inventory[INVEN_HEAD].tval != TV_NOTHING) tmp[k++] = INVEN_HEAD; /* also enchant boots */ if (inventory[INVEN_FEET].tval != TV_NOTHING) tmp[k++] = INVEN_FEET; if (k > 0) l = tmp[randint(k)-1]; #ifdef ATARIST_MWC if (holder & inventory[INVEN_BODY].flags) l = INVEN_BODY; else if (holder & inventory[INVEN_ARM].flags) l = INVEN_ARM; else if (holder & inventory[INVEN_OUTER].flags) l = INVEN_OUTER; else if (holder & inventory[INVEN_HEAD].flags) l = INVEN_HEAD; else if (holder & inventory[INVEN_HANDS].flags) l = INVEN_HANDS; else if (holder & inventory[INVEN_FEET].flags) l = INVEN_FEET; #else if (TR_CURSED & inventory[INVEN_BODY].flags) l = INVEN_BODY; else if (TR_CURSED & inventory[INVEN_ARM].flags) l = INVEN_ARM; else if (TR_CURSED & inventory[INVEN_OUTER].flags) l = INVEN_OUTER; else if (TR_CURSED & inventory[INVEN_HEAD].flags) l = INVEN_HEAD; else if (TR_CURSED & inventory[INVEN_HANDS].flags) l = INVEN_HANDS; else if (TR_CURSED & inventory[INVEN_FEET].flags) l = INVEN_FEET; #endif if (l > 0) { i_ptr = &inventory[l]; objdes(tmp_str, i_ptr, FALSE); (void) sprintf(out_val, "Your %s glows faintly!", tmp_str); msg_print(out_val); if (enchant(&i_ptr->toac, 10)) { #ifdef ATARIST_MWC i_ptr->flags &= ~holder; #else i_ptr->flags &= ~TR_CURSED; #endif calc_bonuses (); } else msg_print("The enchantment fails."); ident = TRUE; } break; case 4: msg_print("This is an identify scroll."); ident = TRUE; used_up = ident_spell(); /* The identify may merge objects, causing the identify scroll to move to a different place. Check for that here. It can move arbitrarily far if an identify scroll was used on another identify scroll, but it always moves down. */ while (i_ptr->tval != TV_SCROLL1 || i_ptr->flags != 0x00000008) { item_val--; i_ptr = &inventory[item_val]; } break; case 5: if (remove_curse()) { msg_print("You feel as if someone is watching over you."); ident = TRUE; } break; case 6: ident = light_area(char_row, char_col); break; case 7: for (k = 0; k < randint(3); k++) { y = char_row; x = char_col; ident |= summon_monster(&y, &x, FALSE); } break; case 8: teleport(10); ident = TRUE; break; case 9: teleport(100); ident = TRUE; break; case 10: dun_level += (-3) + 2*randint(2); if (dun_level < 1) dun_level = 1; new_level_flag = TRUE; ident = TRUE; break; case 11: if (py.flags.confuse_monster == 0) { msg_print("Your hands begin to glow."); py.flags.confuse_monster = TRUE; ident = TRUE; } break; case 12: ident = TRUE; map_area(); break; case 13: ident = sleep_monsters1(char_row, char_col); break; case 14: ident = TRUE; warding_glyph(); break; case 15: ident = detect_treasure(); break; case 16: ident = detect_object(); break; case 17: ident = detect_trap(); break; case 18: ident = detect_sdoor(); break; case 19: msg_print("This is a mass genocide scroll."); (void) mass_genocide(); ident = TRUE; break; case 20: ident = detect_invisible(); break; case 21: msg_print("There is a high pitched humming noise."); (void) aggravate_monster(20); ident = TRUE; break; case 22: ident = trap_creation(); break; case 23: ident = td_destroy(); break; case 24: ident = door_creation(); break; case 25: msg_print("This is a Recharge-Item scroll."); ident = TRUE; used_up = recharge(60); break; case 26: msg_print("This is a genocide scroll."); (void) genocide(); ident = TRUE; break; case 27: ident = unlight_area(char_row, char_col); break; case 28: ident = protect_evil(); break; case 29: ident = TRUE; create_food(); break; case 30: ident = dispel_creature(CD_UNDEAD, 60); break; case 33: i_ptr = &inventory[INVEN_WIELD]; if (i_ptr->tval != TV_NOTHING) { objdes(tmp_str, i_ptr, FALSE); (void) sprintf(out_val, "Your %s glows brightly!", tmp_str); msg_print(out_val); flag = FALSE; for (k = 0; k < randint(2); k++) if (enchant(&i_ptr->tohit, 10)) flag = TRUE; if ((i_ptr->tval >= TV_HAFTED)&&(i_ptr->tval <= TV_DIGGING)) j = i_ptr->damage[0] * i_ptr->damage[1]; else /* Bows' and arrows' enchantments should not be limited by their low base damages */ j = 10; for (k = 0; k < randint(2); k++) if (enchant(&i_ptr->todam, j)) flag = TRUE; if (flag) { #ifdef ATARIST_MWC i_ptr->flags &= ~holder; #else i_ptr->flags &= ~TR_CURSED; #endif calc_bonuses (); } else msg_print("The enchantment fails."); ident = TRUE; } break; case 34: i_ptr = &inventory[INVEN_WIELD]; if (i_ptr->tval != TV_NOTHING) { objdes(tmp_str, i_ptr, FALSE); (void)sprintf(out_val,"Your %s glows black, fades.",tmp_str); msg_print(out_val); unmagic_name(i_ptr); i_ptr->tohit = -randint(5) - randint(5); i_ptr->todam = -randint(5) - randint(5); i_ptr->toac = 0; /* Must call py_bonuses() before set (clear) flags, and must call calc_bonuses() after set (clear) flags, so that all attributes will be properly turned off. */ py_bonuses(i_ptr, -1); i_ptr->flags = TR_CURSED; calc_bonuses (); ident = TRUE; } break; case 35: k = 0; l = 0; if (inventory[INVEN_BODY].tval != TV_NOTHING) tmp[k++] = INVEN_BODY; if (inventory[INVEN_ARM].tval != TV_NOTHING) tmp[k++] = INVEN_ARM; if (inventory[INVEN_OUTER].tval != TV_NOTHING) tmp[k++] = INVEN_OUTER; if (inventory[INVEN_HANDS].tval != TV_NOTHING) tmp[k++] = INVEN_HANDS; if (inventory[INVEN_HEAD].tval != TV_NOTHING) tmp[k++] = INVEN_HEAD; /* also enchant boots */ if (inventory[INVEN_FEET].tval != TV_NOTHING) tmp[k++] = INVEN_FEET; if (k > 0) l = tmp[randint(k)-1]; #ifdef ATARIST_MWC if (holder & inventory[INVEN_BODY].flags) l = INVEN_BODY; else if (holder & inventory[INVEN_ARM].flags) l = INVEN_ARM; else if (holder & inventory[INVEN_OUTER].flags) l = INVEN_OUTER; else if (holder & inventory[INVEN_HEAD].flags) l = INVEN_HEAD; else if (holder & inventory[INVEN_HANDS].flags) l = INVEN_HANDS; else if (holder & inventory[INVEN_FEET].flags) l = INVEN_FEET; #else if (TR_CURSED & inventory[INVEN_BODY].flags) l = INVEN_BODY; else if (TR_CURSED & inventory[INVEN_ARM].flags) l = INVEN_ARM; else if (TR_CURSED & inventory[INVEN_OUTER].flags) l = INVEN_OUTER; else if (TR_CURSED & inventory[INVEN_HEAD].flags) l = INVEN_HEAD; else if (TR_CURSED & inventory[INVEN_HANDS].flags) l = INVEN_HANDS; else if (TR_CURSED & inventory[INVEN_FEET].flags) l = INVEN_FEET; #endif if (l > 0) { i_ptr = &inventory[l]; objdes(tmp_str, i_ptr, FALSE); (void) sprintf(out_val,"Your %s glows brightly!", tmp_str); msg_print(out_val); flag = FALSE; for (k = 0; k < randint(2) + 1; k++) if (enchant(&i_ptr->toac, 10)) flag = TRUE; if (flag) { #ifdef ATARIST_MWC i_ptr->flags &= ~holder; #else i_ptr->flags &= ~TR_CURSED; #endif calc_bonuses (); } else msg_print("The enchantment fails."); ident = TRUE; } break; case 36: if ((inventory[INVEN_BODY].tval != TV_NOTHING) && (randint(4) == 1)) k = INVEN_BODY; else if ((inventory[INVEN_ARM].tval != TV_NOTHING) && (randint(3) ==1)) k = INVEN_ARM; else if ((inventory[INVEN_OUTER].tval != TV_NOTHING) && (randint(3) ==1)) k = INVEN_OUTER; else if ((inventory[INVEN_HEAD].tval != TV_NOTHING) && (randint(3) ==1)) k = INVEN_HEAD; else if ((inventory[INVEN_HANDS].tval != TV_NOTHING) && (randint(3) ==1)) k = INVEN_HANDS; else if ((inventory[INVEN_FEET].tval != TV_NOTHING) && (randint(3) ==1)) k = INVEN_FEET; else if (inventory[INVEN_BODY].tval != TV_NOTHING) k = INVEN_BODY; else if (inventory[INVEN_ARM].tval != TV_NOTHING) k = INVEN_ARM; else if (inventory[INVEN_OUTER].tval != TV_NOTHING) k = INVEN_OUTER; else if (inventory[INVEN_HEAD].tval != TV_NOTHING) k = INVEN_HEAD; else if (inventory[INVEN_HANDS].tval != TV_NOTHING) k = INVEN_HANDS; else if (inventory[INVEN_FEET].tval != TV_NOTHING) k = INVEN_FEET; else k = 0; if (k > 0) { i_ptr = &inventory[k]; objdes(tmp_str, i_ptr, FALSE); (void)sprintf(out_val,"Your %s glows black, fades.",tmp_str); msg_print(out_val); unmagic_name(i_ptr); i_ptr->flags = TR_CURSED; i_ptr->tohit = 0; i_ptr->todam = 0; i_ptr->toac = -randint(5) - randint(5); calc_bonuses (); ident = TRUE; } break; case 37: ident = FALSE; for (k = 0; k < randint(3); k++) { y = char_row; x = char_col; ident |= summon_undead(&y, &x); } break; case 38: ident = TRUE; bless(randint(12)+6); break; case 39: ident = TRUE; bless(randint(24)+12); break; case 40: ident = TRUE; bless(randint(48)+24); break; case 41: ident = TRUE; if (py.flags.word_recall == 0) py.flags.word_recall = 25 + randint(30); msg_print("The air about you becomes charged."); break; case 42: destroy_area(char_row, char_col); ident = TRUE; break; default: msg_print("Internal error in scroll()"); break; } /* End of Scrolls. */ } i_ptr = &inventory[item_val]; if (ident) { if (!known1_p(i_ptr)) { m_ptr = &py.misc; /* round half-way case up */ m_ptr->exp += (i_ptr->level +(m_ptr->lev >> 1)) / m_ptr->lev; prt_experience(); identify(&item_val); i_ptr = &inventory[item_val]; } } else if (!known1_p(i_ptr)) sample (i_ptr); if (used_up) { desc_remain(item_val); inven_destroy(item_val); } } } moria-5.6.debian.1/source/desc.c0000644000175000017500000004255011074756544014570 0ustar pjbpjb/* source/desc.c: handle object descriptions, mostly string handling code Copyright (c) 1989-94 James E. Wilson, Robert A. Koeneke This software may be copied and distributed for educational, research, and not for profit purposes provided that this copyright and statement are included in all such copies. */ #include #include #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #ifdef USG #ifndef ATARIST_MWC #include #endif #else #include #endif #if defined(LINT_ARGS) static void unsample(struct inven_type *); #else static void unsample(); #endif #ifdef ATARIST_TC /* Include this to get prototypes for standard library functions. */ #include #endif char titles[MAX_TITLES][10]; /* Object descriptor routines */ int is_a_vowel(ch) char ch; { switch(ch) { case 'a': case 'e': case 'i': case 'o': case 'u': case 'A': case 'E': case 'I': case 'O': case 'U': return(TRUE); default: return(FALSE); } } /* Initialize all Potions, wands, staves, scrolls, etc. */ void magic_init() { register int h, i, j, k; register char *tmp; vtype string; set_seed(randes_seed); /* The first 3 entries for colors are fixed, (slime & apple juice, water) */ for (i = 3; i < MAX_COLORS; i++) { j = randint(MAX_COLORS - 3) + 2; tmp = colors[i]; colors[i] = colors[j]; colors[j] = tmp; } for (i = 0; i < MAX_WOODS; i++) { j = randint(MAX_WOODS) - 1; tmp = woods[i]; woods[i] = woods[j]; woods[j] = tmp; } for (i = 0; i < MAX_METALS; i++) { j = randint(MAX_METALS) - 1; tmp = metals[i]; metals[i] = metals[j]; metals[j] = tmp; } for (i = 0; i < MAX_ROCKS; i++) { j = randint(MAX_ROCKS) - 1; tmp = rocks[i]; rocks[i] = rocks[j]; rocks[j] = tmp; } for (i = 0; i < MAX_AMULETS; i++) { j = randint(MAX_AMULETS) - 1; tmp = amulets[i]; amulets[i] = amulets[j]; amulets[j] = tmp; } for (i = 0; i < MAX_MUSH; i++) { j = randint(MAX_MUSH) - 1; tmp = mushrooms[i]; mushrooms[i] = mushrooms[j]; mushrooms[j] = tmp; } for (h = 0; h < MAX_TITLES; h++) { string[0] = '\0'; k = randint(2) + 1; for (i = 0; i < k; i++) { for (j = randint(2); j > 0; j--) (void) strcat(string, syllables[randint(MAX_SYLLABLES) - 1]); if (i < k-1) (void) strcat(string, " "); } if (string[8] == ' ') string[8] = '\0'; else string[9] = '\0'; (void) strcpy(titles[h], string); } reset_seed(); } int16 object_offset(t_ptr) inven_type *t_ptr; { switch (t_ptr->tval) { case TV_AMULET: return(0); case TV_RING: return(1); case TV_STAFF: return(2); case TV_WAND: return(3); case TV_SCROLL1: case TV_SCROLL2: return(4); case TV_POTION1: case TV_POTION2: return(5); case TV_FOOD: if ((t_ptr->subval & (ITEM_SINGLE_STACK_MIN - 1)) < MAX_MUSH) return(6); return(-1); default: return(-1); } } /* Remove "Secret" symbol for identity of object */ void known1(i_ptr) inven_type *i_ptr; { int16 offset; int8u indexx; if ((offset = object_offset(i_ptr)) < 0) return; offset <<= 6; indexx = i_ptr->subval & (ITEM_SINGLE_STACK_MIN - 1); object_ident[offset + indexx] |= OD_KNOWN1; /* clear the tried flag, since it is now known */ object_ident[offset + indexx] &= ~OD_TRIED; } int known1_p(i_ptr) inven_type *i_ptr; { int16 offset; int8u indexx; /* Items which don't have a 'color' are always known1, so that they can be carried in order in the inventory. */ if ((offset = object_offset(i_ptr)) < 0) return OD_KNOWN1; if (store_bought_p(i_ptr)) return OD_KNOWN1; offset <<= 6; indexx = i_ptr->subval & (ITEM_SINGLE_STACK_MIN - 1); return(object_ident[offset + indexx] & OD_KNOWN1); } /* Remove "Secret" symbol for identity of plusses */ void known2(i_ptr) inven_type *i_ptr; { unsample(i_ptr); i_ptr->ident |= ID_KNOWN2; } int known2_p(i_ptr) inven_type *i_ptr; { return (i_ptr->ident & ID_KNOWN2); } void clear_known2(i_ptr) inven_type *i_ptr; { i_ptr->ident &= ~ID_KNOWN2; } void clear_empty(i_ptr) inven_type *i_ptr; { i_ptr->ident &= ~ID_EMPTY; } void store_bought(i_ptr) inven_type *i_ptr; { i_ptr->ident |= ID_STOREBOUGHT; known2(i_ptr); } int store_bought_p(i_ptr) inven_type *i_ptr; { return (i_ptr->ident & ID_STOREBOUGHT); } /* Remove an automatically generated inscription. -CJS- */ static void unsample(i_ptr) inven_type *i_ptr; { int16 offset; int8u indexx; /* used to clear ID_DAMD flag, but I think it should remain set */ i_ptr->ident &= ~(ID_MAGIK|ID_EMPTY); if ((offset = object_offset(i_ptr)) < 0) return; offset <<= 6; indexx = i_ptr->subval & (ITEM_SINGLE_STACK_MIN - 1); object_ident[offset + indexx] &= ~OD_TRIED; } /* unquote() is no longer needed */ /* Somethings been sampled -CJS- */ void sample (i_ptr) inven_type *i_ptr; { int16 offset; int8u indexx; if ((offset = object_offset(i_ptr)) < 0) return; offset <<= 6; indexx = i_ptr->subval & (ITEM_SINGLE_STACK_MIN - 1); object_ident[offset + indexx] |= OD_TRIED; } /* Somethings been identified */ /* extra complexity by CJS so that it can merge store/dungeon objects when appropriate */ void identify(item) int *item; { register int i, x1, x2; int j; register inven_type *i_ptr, *t_ptr; #ifdef ATARIST_MWC int32u holder; #endif i_ptr = &inventory[*item]; #ifdef ATARIST_MWC if (i_ptr->flags & (holder = TR_CURSED)) #else if (i_ptr->flags & TR_CURSED) #endif add_inscribe(i_ptr, ID_DAMD); if (!known1_p(i_ptr)) { known1(i_ptr); x1 = i_ptr->tval; x2 = i_ptr->subval; if (x2 < ITEM_SINGLE_STACK_MIN || x2 >= ITEM_GROUP_MIN) /* no merging possible */ ; else for (i = 0; i < inven_ctr; i++) { t_ptr = &inventory[i]; if (t_ptr->tval == x1 && t_ptr->subval == x2 && i != *item && ((int)t_ptr->number + (int)i_ptr->number < 256)) { /* make *item the smaller number */ if (*item > i) { j = *item; *item = i; i = j; } msg_print ("You combine similar objects from the shop and dungeon."); inventory[*item].number += inventory[i].number; inven_ctr--; for (j = i; j < inven_ctr; j++) inventory[j] = inventory[j+1]; invcopy(&inventory[j], OBJ_NOTHING); } } } } /* If an object has lost magical properties, * remove the appropriate portion of the name. -CJS- */ void unmagic_name(i_ptr) inven_type *i_ptr; { i_ptr->name2 = SN_NULL; } /* defines for p1_use, determine how the p1 field is printed */ #define IGNORED 0 #define CHARGES 1 #define PLUSSES 2 #define LIGHT 3 #define FLAGS 4 #define Z_PLUSSES 5 /* Returns a description of item for inventory */ /* pref indicates that there should be an article added (prefix) */ /* note that since out_val can easily exceed 80 characters, objdes must always be called with a bigvtype as the first paramter */ void objdes(out_val, i_ptr, pref) char *out_val; register inven_type *i_ptr; int pref; { /* base name, modifier string*/ register char *basenm, *modstr; bigvtype tmp_val; vtype tmp_str, damstr; int indexx, p1_use, modify, append_name, tmp; indexx = i_ptr->subval & (ITEM_SINGLE_STACK_MIN - 1); basenm = object_list[i_ptr->index].name; modstr = CNIL; damstr[0] = '\0'; p1_use = IGNORED; modify = (known1_p(i_ptr) ? FALSE : TRUE); append_name = FALSE; switch(i_ptr->tval) { case TV_MISC: case TV_CHEST: break; case TV_SLING_AMMO: case TV_BOLT: case TV_ARROW: (void) sprintf(damstr, " (%dd%d)", i_ptr->damage[0], i_ptr->damage[1]); break; case TV_LIGHT: p1_use = LIGHT; break; case TV_SPIKE: break; case TV_BOW: if (i_ptr->p1 == 1 || i_ptr->p1 == 2) tmp = 2; else if (i_ptr->p1 == 3 || i_ptr->p1 == 5) tmp = 3; else if (i_ptr->p1 == 4 || i_ptr->p1 == 6) tmp = 4; else tmp = -1; (void) sprintf (damstr, " (x%d)", tmp); break; case TV_HAFTED: case TV_POLEARM: case TV_SWORD: (void) sprintf(damstr, " (%dd%d)", i_ptr->damage[0], i_ptr->damage[1]); p1_use = FLAGS; break; case TV_DIGGING: p1_use = Z_PLUSSES; (void) sprintf(damstr, " (%dd%d)", i_ptr->damage[0], i_ptr->damage[1]); break; case TV_BOOTS: case TV_GLOVES: case TV_CLOAK: case TV_HELM: case TV_SHIELD: case TV_HARD_ARMOR: case TV_SOFT_ARMOR: break; case TV_AMULET: if (modify) { basenm = "& %s Amulet"; modstr = amulets[indexx]; } else { basenm = "& Amulet"; append_name = TRUE; } p1_use = PLUSSES; break; case TV_RING: if (modify) { basenm = "& %s Ring"; modstr = rocks[indexx]; } else { basenm = "& Ring"; append_name = TRUE; } p1_use = PLUSSES; break; case TV_STAFF: if (modify) { basenm = "& %s Staff"; modstr = woods[indexx]; } else { basenm = "& Staff"; append_name = TRUE; } p1_use = CHARGES; break; case TV_WAND: if (modify) { basenm = "& %s Wand"; modstr = metals[indexx]; } else { basenm = "& Wand"; append_name = TRUE; } p1_use = CHARGES; break; case TV_SCROLL1: case TV_SCROLL2: if (modify) { basenm = "& Scroll~ titled \"%s\""; modstr = titles[indexx]; } else { basenm = "& Scroll~"; append_name = TRUE; } break; case TV_POTION1: case TV_POTION2: if (modify) { basenm = "& %s Potion~"; modstr = colors[indexx]; } else { basenm = "& Potion~"; append_name = TRUE; } break; case TV_FLASK: break; case TV_FOOD: if (modify) { if (indexx <= 15) basenm = "& %s Mushroom~"; else if (indexx <= 20) basenm = "& Hairy %s Mold~"; if (indexx <= 20) modstr = mushrooms[indexx]; } else { append_name = TRUE; if (indexx <= 15) basenm = "& Mushroom~"; else if (indexx <= 20) basenm = "& Hairy Mold~"; else /* Ordinary food does not have a name appended. */ append_name = FALSE; } break; case TV_MAGIC_BOOK: modstr = basenm; basenm = "& Book~ of Magic Spells %s"; break; case TV_PRAYER_BOOK: modstr = basenm; basenm = "& Holy Book~ of Prayers %s"; break; case TV_OPEN_DOOR: case TV_CLOSED_DOOR: case TV_SECRET_DOOR: case TV_RUBBLE: break; case TV_GOLD: case TV_INVIS_TRAP: case TV_VIS_TRAP: case TV_UP_STAIR: case TV_DOWN_STAIR: (void) strcpy(out_val, object_list[i_ptr->index].name); (void) strcat(out_val, "."); return; case TV_STORE_DOOR: (void) sprintf(out_val, "the entrance to the %s.", object_list[i_ptr->index].name); return; default: (void) strcpy(out_val, "Error in objdes()"); return; } if (modstr != CNIL) (void) sprintf(tmp_val, basenm, modstr); else (void) strcpy(tmp_val, basenm); if (append_name) { (void) strcat(tmp_val, " of "); (void) strcat(tmp_val, object_list[i_ptr->index].name); } if (i_ptr->number != 1) { insert_str(tmp_val, "ch~", "ches"); insert_str(tmp_val, "~", "s"); } else insert_str(tmp_val, "~", CNIL); if (!pref) { if (!strncmp("some", tmp_val, 4)) (void) strcpy(out_val, &tmp_val[5]); else if (tmp_val[0] == '&') /* eliminate the '& ' at the beginning */ (void) strcpy(out_val, &tmp_val[2]); else (void) strcpy(out_val, tmp_val); } else { if (i_ptr->name2 != SN_NULL && known2_p(i_ptr)) { (void) strcat(tmp_val, " "); (void) strcat(tmp_val, special_names[i_ptr->name2]); } if (damstr[0] != '\0') (void) strcat(tmp_val, damstr); if (known2_p(i_ptr)) { /* originally used %+d, but several machines don't support it */ if (i_ptr->ident & ID_SHOW_HITDAM) (void) sprintf(tmp_str, " (%c%d,%c%d)", (i_ptr->tohit < 0) ? '-' : '+', abs(i_ptr->tohit), (i_ptr->todam < 0) ? '-' : '+', abs(i_ptr->todam)); else if (i_ptr->tohit != 0) (void) sprintf(tmp_str, " (%c%d)", (i_ptr->tohit < 0) ? '-' : '+', abs(i_ptr->tohit)); else if (i_ptr->todam != 0) (void) sprintf(tmp_str, " (%c%d)", (i_ptr->todam < 0) ? '-' : '+', abs(i_ptr->todam)); else tmp_str[0] = '\0'; (void) strcat(tmp_val, tmp_str); } /* Crowns have a zero base AC, so make a special test for them. */ if (i_ptr->ac != 0 || (i_ptr->tval == TV_HELM)) { (void) sprintf(tmp_str, " [%d", i_ptr->ac); (void) strcat(tmp_val, tmp_str); if (known2_p(i_ptr)) { /* originally used %+d, but several machines don't support it */ (void) sprintf(tmp_str, ",%c%d", (i_ptr->toac < 0) ? '-' : '+', abs(i_ptr->toac)); (void) strcat(tmp_val, tmp_str); } (void) strcat(tmp_val, "]"); } else if ((i_ptr->toac != 0) && known2_p(i_ptr)) { /* originally used %+d, but several machines don't support it */ (void) sprintf(tmp_str, " [%c%d]", (i_ptr->toac < 0) ? '-' : '+', abs(i_ptr->toac)); (void) strcat(tmp_val, tmp_str); } /* override defaults, check for p1 flags in the ident field */ if (i_ptr->ident & ID_NOSHOW_P1) p1_use = IGNORED; else if (i_ptr->ident & ID_SHOW_P1) p1_use = Z_PLUSSES; tmp_str[0] = '\0'; if (p1_use == LIGHT) (void) sprintf(tmp_str, " with %d turns of light", i_ptr->p1); else if (p1_use == IGNORED) ; else if (known2_p(i_ptr)) { if (p1_use == Z_PLUSSES) /* originally used %+d, but several machines don't support it */ (void) sprintf(tmp_str, " (%c%d)", (i_ptr->p1 < 0) ? '-' : '+', abs(i_ptr->p1)); else if (p1_use == CHARGES) (void) sprintf(tmp_str, " (%d charges)", i_ptr->p1); else if (i_ptr->p1 != 0) { if (p1_use == PLUSSES) (void) sprintf(tmp_str, " (%c%d)", (i_ptr->p1 < 0) ? '-' : '+', abs(i_ptr->p1)); else if (p1_use == FLAGS) { if (i_ptr->flags & TR_STR) (void) sprintf(tmp_str, " (%c%d to STR)", (i_ptr->p1 < 0) ? '-' : '+',abs(i_ptr->p1)); else if (i_ptr->flags & TR_STEALTH) (void) sprintf(tmp_str, " (%c%d to stealth)", (i_ptr->p1 < 0) ? '-' : '+',abs(i_ptr->p1)); } } } (void) strcat(tmp_val, tmp_str); /* ampersand is always the first character */ if (tmp_val[0] == '&') { /* use &tmp_val[1], so that & does not appear in output */ if (i_ptr->number > 1) (void) sprintf(out_val, "%d%s", (int)i_ptr->number, &tmp_val[1]); else if (i_ptr->number < 1) (void) sprintf(out_val, "%s%s", "no more", &tmp_val[1]); else if (is_a_vowel(tmp_val[2])) (void) sprintf(out_val, "an%s", &tmp_val[1]); else (void) sprintf(out_val, "a%s", &tmp_val[1]); } /* handle 'no more' case specially */ else if (i_ptr->number < 1) { /* check for "some" at start */ if (!strncmp("some", tmp_val, 4)) (void) sprintf(out_val, "no more %s", &tmp_val[5]); /* here if no article */ else (void) sprintf(out_val, "no more %s", tmp_val); } else (void) strcpy(out_val, tmp_val); tmp_str[0] = '\0'; if ((indexx = object_offset(i_ptr)) >= 0) { indexx = (indexx <<= 6) + (i_ptr->subval & (ITEM_SINGLE_STACK_MIN - 1)); /* don't print tried string for store bought items */ if ((object_ident[indexx] & OD_TRIED) && !store_bought_p(i_ptr)) (void) strcat(tmp_str, "tried "); } if (i_ptr->ident & (ID_MAGIK|ID_EMPTY|ID_DAMD)) { if (i_ptr->ident & ID_MAGIK) (void) strcat(tmp_str, "magik "); if (i_ptr->ident & ID_EMPTY) (void) strcat(tmp_str, "empty "); if (i_ptr->ident & ID_DAMD) (void) strcat(tmp_str, "damned "); } if (i_ptr->inscrip[0] != '\0') (void) strcat(tmp_str, i_ptr->inscrip); else if ((indexx = strlen(tmp_str)) > 0) /* remove the extra blank at the end */ tmp_str[indexx-1] = '\0'; if (tmp_str[0]) { (void) sprintf(tmp_val, " {%s}", tmp_str); (void) strcat(out_val, tmp_val); } (void) strcat(out_val, "."); } } void invcopy(to, from_index) register inven_type *to; int from_index; { register treasure_type *from; from = &object_list[from_index]; to->index = from_index; to->name2 = SN_NULL; to->inscrip[0] = '\0'; to->flags = from->flags; to->tval = from->tval; to->tchar = from->tchar; to->p1 = from->p1; to->cost = from->cost; to->subval = from->subval; to->number = from->number; to->weight = from->weight; to->tohit = from->tohit; to->todam = from->todam; to->ac = from->ac; to->toac = from->toac; to->damage[0] = from->damage[0]; to->damage[1] = from->damage[1]; to->level = from->level; to->ident = 0; } /* Describe number of remaining charges. -RAK- */ void desc_charges(item_val) int item_val; { register int rem_num; vtype out_val; if (known2_p(&inventory[item_val])) { rem_num = inventory[item_val].p1; (void) sprintf(out_val, "You have %d charges remaining.", rem_num); msg_print(out_val); } } /* Describe amount of item remaining. -RAK- */ void desc_remain(item_val) int item_val; { bigvtype out_val, tmp_str; register inven_type *i_ptr; i_ptr = &inventory[item_val]; i_ptr->number--; objdes(tmp_str, i_ptr, TRUE); i_ptr->number++; /* the string already has a dot at the end. */ (void) sprintf(out_val, "You have %s", tmp_str); msg_print(out_val); } moria-5.6.debian.1/source/treasure.c0000644000175000017500000014750611074756544015513 0ustar pjbpjb/* source/treasure.c: dungeon object definitions Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include "config.h" #include "constant.h" #include "types.h" /* Following are treasure arrays and variables */ /* Object description: Objects are defined here. Each object has the following attributes: Descriptor : Name of item and formats. & is replaced with 'a', 'an', or a number. ~ is replaced with null or 's'. Character : Character that represents the item. Type value : Value representing the type of object. Sub value : separate value for each item of a type. 0 - 63: object can not stack 64 - 127: dungeon object, can stack with other D object 128 - 191: unused, previously for store items 192: stack with other iff have same p1 value, always treated as individual objects 193 - 255: object can stack with others iff they have the same p1 value, usually considered one group Objects which have two type values, e.g. potions and scrolls, need to have distinct subvals for each item regardless of its tval Damage : amount of damage item can cause. Weight : relative weight of an item. Number : number of items appearing in group. To hit : magical plusses to hit. To damage : magical plusses to damage. AC : objects relative armor class. 1 is worse than 5 is worse than 10 etc. To AC : Magical bonuses to AC. P1 : Catch all for magical abilities such as plusses to strength, minuses to searching. Flags : Abilities of object. Each ability is a bit. Bits 1-31 are used. (Signed integer) Level : Minimum level on which item can be found. Cost : Relative cost of item. Special Abilities can be added to item by magic_init(), found in misc.c. Scrolls, Potions, and Food: Flags is used to define a function which reading/quaffing will cause. Most scrolls and potions have only one bit set. Potions will generally have some food value, found in p1. Wands and Staffs: Flags defines a function, p1 contains number of charges for item. p1 is set in magic_init() in misc.c. Chests: Traps are added randomly by magic_init() in misc.c. */ /* Object list (All objects must be defined here) */ #if defined(MACGAME) || defined(RSRC_PART2) treasure_type *object_list; #else treasure_type object_list[MAX_OBJECTS] = { /* Dungeon items from 0 to MAX_DUNGEON_OBJ */ {"Poison" ,0x00000001L, TV_FOOD, ',', /* 0*/ 500, 0, 64, 1, 1, 0, 0, 0, 0, {0,0} , 7}, {"Blindness" ,0x00000002L, TV_FOOD, ',', /* 1*/ 500, 0, 65, 1, 1, 0, 0, 0, 0, {0,0} , 9}, {"Paranoia" ,0x00000004L, TV_FOOD, ',', /* 2*/ 500, 0, 66, 1, 1, 0, 0, 0, 0, {0,0} , 9}, {"Confusion" ,0x00000008L, TV_FOOD, ',', /* 3*/ 500, 0, 67, 1, 1, 0, 0, 0, 0, {0,0} , 7}, {"Hallucination" ,0x00000010L, TV_FOOD, ',', /* 4*/ 500, 0, 68, 1, 1, 0, 0, 0, 0, {0,0} , 13}, {"Cure Poison" ,0x00000020L, TV_FOOD, ',', /* 5*/ 500, 60, 69, 1, 1, 0, 0, 0, 0, {0,0} , 8}, {"Cure Blindness" ,0x00000040L, TV_FOOD, ',', /* 6*/ 500, 50, 70, 1, 1, 0, 0, 0, 0, {0,0} , 10}, {"Cure Paranoia" ,0x00000080L, TV_FOOD, ',', /* 7*/ 500, 25, 71, 1, 1, 0, 0, 0, 0, {0,0} , 12}, {"Cure Confusion" ,0x00000100L, TV_FOOD, ',', /* 8*/ 500, 50, 72, 1, 1, 0, 0, 0, 0, {0,0} , 6}, {"Weakness" ,0x04000200L, TV_FOOD, ',', /* 9*/ 500, 0, 73, 1, 1, 0, 0, 0, 0, {0,0} , 7}, {"Unhealth" ,0x04000400L, TV_FOOD, ',', /* 10*/ 500, 50, 74, 1, 1, 0, 0, 0, 0, {10,10}, 15}, {"Restore Constitution" ,0x00010000L, TV_FOOD, ',', /* 11*/ 500, 350, 75, 1, 1, 0, 0, 0, 0, {0,0} , 20}, {"First-Aid" ,0x00200000L, TV_FOOD, ',', /* 12*/ 500, 5, 76, 1, 1, 0, 0, 0, 0, {0,0} , 6}, {"Minor Cures" ,0x00400000L, TV_FOOD, ',', /* 13*/ 500, 20, 77, 1, 1, 0, 0, 0, 0, {0,0} , 7}, {"Light Cures" ,0x00800000L, TV_FOOD, ',', /* 14*/ 500, 30, 78, 1, 1, 0, 0, 0, 0, {0,0} , 10}, {"Restoration" ,0x001F8000L, TV_FOOD, ',', /* 15*/ 500, 1000, 79, 1, 1, 0, 0, 0, 0, {0,0} , 30}, {"Poison" ,0x00000001L, TV_FOOD, ',', /* 16*/ 1200, 0, 80, 1, 1, 0, 0, 0, 0, {0,0} , 15}, {"Hallucination" ,0x00000010L, TV_FOOD, ',', /* 17*/ 1200, 0, 81, 1, 1, 0, 0, 0, 0, {0,0} , 18}, {"Cure Poison" ,0x00000020L, TV_FOOD, ',', /* 18*/ 1200, 75, 82, 1, 1, 0, 0, 0, 0, {0,0} , 19}, {"Unhealth" ,0x04000400L, TV_FOOD, ',', /* 19*/ 1200, 75, 83, 1, 1, 0, 0, 0, 0, {10,12}, 28}, {"Major Cures" ,0x02000000L, TV_FOOD, ',', /* 20*/ 1200, 75, 84, 1, 2, 0, 0, 0, 0, {0,0} , 16}, {"& Ration~ of Food" ,0x00000000L, TV_FOOD, ',', /* 21*/ 5000, 3, 90, 1, 10, 0, 0, 0, 0, {0,0} , 0}, {"& Ration~ of Food" ,0x00000000L, TV_FOOD, ',', /* 22*/ 5000, 3, 90, 1, 10, 0, 0, 0, 0, {0,0} , 5}, {"& Ration~ of Food" ,0x00000000L, TV_FOOD, ',', /* 23*/ 5000, 3, 90, 1, 10, 0, 0, 0, 0, {0,0} , 10}, {"& Slime Mold~" ,0x00000000L, TV_FOOD, ',', /* 24*/ 3000, 2, 91, 1, 5, 0, 0, 0, 0, {0,0} , 1}, {"& Piece~ of Elvish Waybread" ,0x02000020L, TV_FOOD, ',', /* 25*/ 7500, 25, 92, 1, 3, 0, 0, 0, 0, {0,0} , 6}, {"& Piece~ of Elvish Waybread" ,0x02000020L, TV_FOOD, ',', /* 26*/ 7500, 25, 92, 1, 3, 0, 0, 0, 0, {0,0} , 12}, {"& Piece~ of Elvish Waybread" ,0x02000020L, TV_FOOD, ',', /* 27*/ 7500, 25, 92, 1, 3, 0, 0, 0, 0, {0,0} , 20}, {"& Dagger (Main Gauche)" ,0x00000000L, TV_SWORD, '|', /* 28*/ 0, 25, 1, 1, 30, 0, 0, 0, 0, {1,5} , 2}, {"& Dagger (Misericorde)" ,0x00000000L, TV_SWORD, '|', /* 29*/ 0, 10, 2, 1, 15, 0, 0, 0, 0, {1,4} , 0}, {"& Dagger (Stiletto)" ,0x00000000L, TV_SWORD, '|', /* 30*/ 0, 10, 3, 1, 12, 0, 0, 0, 0, {1,4} , 0}, {"& Dagger (Bodkin)" ,0x00000000L, TV_SWORD, '|', /* 31*/ 0, 10, 4, 1, 20, 0, 0, 0, 0, {1,4} , 1}, {"& Broken Dagger" ,0x00000000L, TV_SWORD, '|', /* 32*/ 0, 0, 5, 1, 15, -2, -2, 0, 0, {1,1} , 0}, {"& Backsword" ,0x00000000L, TV_SWORD, '|', /* 33*/ 0, 150, 6, 1, 95, 0, 0, 0, 0, {1,9} , 7}, {"& Bastard Sword" ,0x00000000L, TV_SWORD, '|', /* 34*/ 0, 350, 7, 1, 140, 0, 0, 0, 0, {3,4} , 14}, {"& Thrusting Sword (Bilbo)" ,0x00000000L, TV_SWORD, '|', /* 35*/ 0, 60, 8, 1, 80, 0, 0, 0, 0, {1,6} , 4}, {"& Thrusting Sword (Baselard)" ,0x00000000L, TV_SWORD, '|', /* 36*/ 0, 80, 9, 1, 100, 0, 0, 0, 0, {1,7} , 5}, {"& Broadsword" ,0x00000000L, TV_SWORD, '|', /* 37*/ 0, 255, 10, 1, 150, 0, 0, 0, 0, {2,5} , 9}, {"& Two-Handed Sword (Claymore)",0x00000000L, TV_SWORD, '|', /* 38*/ 0, 775, 11, 1, 200, 0, 0, 0, 0, {3,6} , 30}, {"& Cutlass" ,0x00000000L, TV_SWORD, '|', /* 39*/ 0, 85, 12, 1, 110, 0, 0, 0, 0, {1,7} , 7}, {"& Two-Handed Sword (Espadon)" ,0x00000000L, TV_SWORD, '|', /* 40*/ 0, 655, 13, 1, 180, 0, 0, 0, 0, {3,6} , 35}, {"& Executioner's Sword" ,0x00000000L, TV_SWORD, '|', /* 41*/ 0, 850, 14, 1, 260, 0, 0, 0, 0, {4,5} , 40}, {"& Two-Handed Sword (Flamberge)",0x00000000L, TV_SWORD, '|', /* 42*/ 0, 1000, 15, 1, 240, 0, 0, 0, 0, {4,5} , 45}, {"& Foil" ,0x00000000L, TV_SWORD, '|', /* 43*/ 0, 35, 16, 1, 30, 0, 0, 0, 0, {1,5} , 2}, {"& Katana" ,0x00000000L, TV_SWORD, '|', /* 44*/ 0, 400, 17, 1, 120, 0, 0, 0, 0, {3,4} , 18}, {"& Longsword" ,0x00000000L, TV_SWORD, '|', /* 45*/ 0, 200, 18, 1, 130, 0, 0, 0, 0, {1,10} , 12}, {"& Two-Handed Sword (No-Dachi)",0x00000000L, TV_SWORD, '|', /* 46*/ 0, 675, 19, 1, 200, 0, 0, 0, 0, {4,4} , 45}, {"& Rapier" ,0x00000000L, TV_SWORD, '|', /* 47*/ 0, 42, 20, 1, 40, 0, 0, 0, 0, {1,6} , 4}, {"& Sabre" ,0x00000000L, TV_SWORD, '|', /* 48*/ 0, 50, 21, 1, 50, 0, 0, 0, 0, {1,7} , 5}, {"& Small Sword" ,0x00000000L, TV_SWORD, '|', /* 49*/ 0, 48, 22, 1, 75, 0, 0, 0, 0, {1,6} , 5}, {"& Two-Handed Sword (Zweihander)",0x00000000L, TV_SWORD, '|', /* 50*/ 0, 1500, 23, 1, 280, 0, 0, 0, 0, {4,6} , 50}, {"& Broken Sword" ,0x00000000L, TV_SWORD, '|', /* 51*/ 0, 0, 24, 1, 75, -2, -2, 0, 0, {1,1} , 0}, {"& Ball and Chain" ,0x00000000L, TV_HAFTED, '\\',/* 52*/ 0, 200, 1, 1, 150, 0, 0, 0, 0, {2,4} , 20}, {"& Cat-o'-Nine-Tails" ,0x00000000L, TV_HAFTED, '\\',/* 53*/ 0, 14, 2, 1, 40, 0, 0, 0, 0, {1,4} , 3}, {"& Wooden Club" ,0x00000000L, TV_HAFTED, '\\',/* 54*/ 0, 10, 3, 1, 100, 0, 0, 0, 0, {1,3} , 0}, {"& Flail" ,0x00000000L, TV_HAFTED, '\\',/* 55*/ 0, 353, 4, 1, 150, 0, 0, 0, 0, {2,6} , 12}, {"& Two-Handed Great Flail" ,0x00000000L, TV_HAFTED, '\\',/* 56*/ 0, 590, 5, 1, 280, 0, 0, 0, 0, {3,6} , 45}, {"& Morningstar" ,0x00000000L, TV_HAFTED, '\\',/* 57*/ 0, 396, 6, 1, 150, 0, 0, 0, 0, {2,6} , 10}, {"& Mace" ,0x00000000L, TV_HAFTED, '\\',/* 58*/ 0, 130, 7, 1, 120, 0, 0, 0, 0, {2,4} , 6}, {"& War Hammer" ,0x00000000L, TV_HAFTED, '\\',/* 59*/ 0, 225, 8, 1, 120, 0, 0, 0, 0, {3,3} , 5}, {"& Lead-Filled Mace" ,0x00000000L, TV_HAFTED, '\\',/* 60*/ 0, 502, 9, 1, 180, 0, 0, 0, 0, {3,4} , 15}, {"& Awl-Pike" ,0x00000000L, TV_POLEARM, '/',/* 61*/ 0, 200, 1, 1, 160, 0, 0, 0, 0, {1,8} , 8}, {"& Beaked Axe" ,0x00000000L, TV_POLEARM, '/',/* 62*/ 0, 408, 2, 1, 180, 0, 0, 0, 0, {2,6} , 15}, {"& Fauchard" ,0x00000000L, TV_POLEARM, '/',/* 63*/ 0, 326, 3, 1, 170, 0, 0, 0, 0, {1,10} , 17}, {"& Glaive" ,0x00000000L, TV_POLEARM, '/',/* 64*/ 0, 363, 4, 1, 190, 0, 0, 0, 0, {2,6} , 20}, {"& Halberd" ,0x00000000L, TV_POLEARM, '/',/* 65*/ 0, 430, 5, 1, 190, 0, 0, 0, 0, {3,4} , 22}, {"& Lucerne Hammer" ,0x00000000L, TV_POLEARM, '/',/* 66*/ 0, 376, 6, 1, 120, 0, 0, 0, 0, {2,5} , 11}, {"& Pike" ,0x00000000L, TV_POLEARM, '/',/* 67*/ 0, 358, 7, 1, 160, 0, 0, 0, 0, {2,5} , 15}, {"& Spear" ,0x00000000L, TV_POLEARM, '/',/* 68*/ 0, 36, 8, 1, 50, 0, 0, 0, 0, {1,6} , 5}, {"& Lance" ,0x00000000L, TV_POLEARM, '/',/* 69*/ 0, 230, 9, 1, 300, 0, 0, 0, 0, {2,8} , 10}, {"& Javelin" ,0x00000000L, TV_POLEARM, '/',/* 70*/ 0, 18, 10, 1, 30, 0, 0, 0, 0, {1,4} , 4}, {"& Battle Axe (Balestarius)" ,0x00000000L, TV_POLEARM, '/',/* 71*/ 0, 500, 11, 1, 180, 0, 0, 0, 0, {2,8} , 30}, {"& Battle Axe (European)" ,0x00000000L, TV_POLEARM, '/',/* 72*/ 0, 334, 12, 1, 170, 0, 0, 0, 0, {3,4} , 13}, {"& Broad Axe" ,0x00000000L, TV_POLEARM, '/',/* 73*/ 0, 304, 13, 1, 160, 0, 0, 0, 0, {2,6} , 17}, {"& Short Bow" ,0x00000000L, TV_BOW, '}', /* 74*/ 2, 50, 1, 1, 30, 0, 0, 0, 0, {0,0} , 3}, {"& Long Bow" ,0x00000000L, TV_BOW, '}', /* 75*/ 3, 120, 2, 1, 40, 0, 0, 0, 0, {0,0} , 10}, {"& Composite Bow" ,0x00000000L, TV_BOW, '}', /* 76*/ 4, 240, 3, 1, 40, 0, 0, 0, 0, {0,0} , 40}, {"& Light Crossbow" ,0x00000000L, TV_BOW, '}', /* 77*/ 5, 140, 10, 1, 110, 0, 0, 0, 0, {0,0} , 15}, {"& Heavy Crossbow" ,0x00000000L, TV_BOW, '}', /* 78*/ 6, 300, 11, 1, 200, 0, 0, 0, 0, {1,1} , 30}, {"& Sling" ,0x00000000L, TV_BOW, '}', /* 79*/ 1, 5, 20, 1, 5, 0, 0, 0, 0, {0,0} , 1}, {"& Arrow~" ,0x00000000L, TV_ARROW, '{', /* 80*/ 0, 1, 193, 1, 2, 0, 0, 0, 0, {1,4} , 2}, {"& Bolt~" ,0x00000000L, TV_BOLT, '{', /* 81*/ 0, 2, 193, 1, 3, 0, 0, 0, 0, {1,5} , 2}, {"& Rounded Pebble~" ,0x00000000L, TV_SLING_AMMO, '{',/* 82*/ 0, 1, 193, 1, 4, 0, 0, 0, 0, {1,2} , 0}, {"& Iron Shot~" ,0x00000000L, TV_SLING_AMMO, '{',/* 83*/ 0, 2, 194, 1, 5, 0, 0, 0, 0, {1,3} , 3}, {"& Iron Spike~" ,0x00000000L, TV_SPIKE, '~', /* 84*/ 0, 1, 193, 1, 10, 0, 0, 0, 0, {1,1} , 1}, {"& Brass Lantern~" ,0x00000000L, TV_LIGHT, '~', /* 85*/ 7500, 35, 1, 1, 50, 0, 0, 0, 0, {1,1} , 1}, {"& Wooden Torch~" ,0x00000000L, TV_LIGHT, '~', /* 86*/ 4000, 2, 193, 1, 30, 0, 0, 0, 0, {1,1} , 1}, {"& Orcish Pick" ,0x20000000L, TV_DIGGING, '\\',/* 87*/ 2, 500, 2, 1, 180, 0, 0, 0, 0, {1,3} , 20}, {"& Dwarven Pick" ,0x20000000L, TV_DIGGING, '\\',/* 88*/ 3, 1200, 3, 1, 200, 0, 0, 0, 0, {1,4} , 50}, {"& Gnomish Shovel" ,0x20000000L, TV_DIGGING, '\\',/* 89*/ 1, 100, 5, 1, 50, 0, 0, 0, 0, {1,2} , 20}, {"& Dwarven Shovel" ,0x20000000L, TV_DIGGING, '\\',/* 90*/ 2, 250, 6, 1, 120, 0, 0, 0, 0, {1,3} , 40}, {"& Pair of Soft Leather Shoes" ,0x00000000L, TV_BOOTS, ']', /* 91*/ 0, 4, 1, 1, 5, 0, 0, 1, 0, {0,0} , 1}, {"& Pair of Soft Leather Boots" ,0x00000000L, TV_BOOTS, ']', /* 92*/ 0, 7, 2, 1, 20, 0, 0, 2, 0, {1,1} , 4}, {"& Pair of Hard Leather Boots" ,0x00000000L, TV_BOOTS, ']', /* 93*/ 0, 12, 3, 1, 40, 0, 0, 3, 0, {1,1} , 6}, {"& Soft Leather Cap" ,0x00000000L, TV_HELM, ']', /* 94*/ 0, 4, 1, 1, 10, 0, 0, 1, 0, {0,0} , 2}, {"& Hard Leather Cap" ,0x00000000L, TV_HELM, ']', /* 95*/ 0, 12, 2, 1, 15, 0, 0, 2, 0, {0,0} , 4}, {"& Metal Cap" ,0x00000000L, TV_HELM, ']', /* 96*/ 0, 30, 3, 1, 20, 0, 0, 3, 0, {1,1} , 7}, {"& Iron Helm" ,0x00000000L, TV_HELM, ']', /* 97*/ 0, 75, 4, 1, 75, 0, 0, 5, 0, {1,3} , 20}, {"& Steel Helm" ,0x00000000L, TV_HELM, ']', /* 98*/ 0, 200, 5, 1, 60, 0, 0, 6, 0, {1,3} , 40}, {"& Silver Crown" ,0x00000000L, TV_HELM, ']', /* 99*/ 0, 500, 6, 1, 20, 0, 0, 0, 0, {1,1} , 44}, {"& Golden Crown" ,0x00000000L, TV_HELM, ']', /*100*/ 0, 1000, 7, 1, 30, 0, 0, 0, 0, {1,2} , 47}, {"& Jewel-Encrusted Crown" ,0x00000000L, TV_HELM, ']', /*101*/ 0, 2000, 8, 1, 40, 0, 0, 0, 0, {1,3} , 50}, {"& Robe" ,0x00000000L, TV_SOFT_ARMOR, '(',/*102*/ 0, 4, 1, 1, 20, 0, 0, 2, 0, {0,0} , 1}, {"Soft Leather Armor" ,0x00000000L, TV_SOFT_ARMOR, '(',/*103*/ 0, 18, 2, 1, 80, 0, 0, 4, 0, {0,0} , 2}, {"Soft Studded Leather" ,0x00000000L, TV_SOFT_ARMOR, '(',/*104*/ 0, 35, 3, 1, 90, 0, 0, 5, 0, {1,1} , 3}, {"Hard Leather Armor" ,0x00000000L, TV_SOFT_ARMOR, '(',/*105*/ 0, 55, 4, 1, 100, -1, 0, 6, 0, {1,1} , 5}, {"Hard Studded Leather" ,0x00000000L, TV_SOFT_ARMOR, '(',/*106*/ 0, 100, 5, 1, 110, -1, 0, 7, 0, {1,2} , 7}, {"Woven Cord Armor" ,0x00000000L, TV_SOFT_ARMOR, '(',/*107*/ 0, 45, 6, 1, 150, -1, 0, 6, 0, {0,0} , 7}, {"Soft Leather Ring Mail" ,0x00000000L, TV_SOFT_ARMOR, '(',/*108*/ 0, 160, 7, 1, 130, -1, 0, 6, 0, {1,2} , 10}, {"Hard Leather Ring Mail" ,0x00000000L, TV_SOFT_ARMOR, '(',/*109*/ 0, 230, 8, 1, 150, -2, 0, 8, 0, {1,3} , 12}, {"Leather Scale Mail" ,0x00000000L, TV_SOFT_ARMOR, '(',/*110*/ 0, 330, 9, 1, 140, -1, 0, 11, 0, {1,1} , 14}, {"Metal Scale Mail" ,0x00000000L, TV_HARD_ARMOR, '[',/*111*/ 0, 430, 1, 1, 250, -2, 0, 13, 0, {1,4} , 24}, {"Chain Mail" ,0x00000000L, TV_HARD_ARMOR, '[',/*112*/ 0, 530, 2, 1, 220, -2, 0, 14, 0, {1,4} , 26}, {"Rusty Chain Mail" ,0x00000000L, TV_HARD_ARMOR, '[',/*113*/ 0, 0, 3, 1, 220, -5, 0, 14, -8, {1,4} , 26}, {"Double Chain Mail" ,0x00000000L, TV_HARD_ARMOR, '[',/*114*/ 0, 630, 4, 1, 260, -2, 0, 15, 0, {1,4} , 28}, {"Augmented Chain Mail" ,0x00000000L, TV_HARD_ARMOR, '[',/*115*/ 0, 675, 5, 1, 270, -2, 0, 16, 0, {1,4} , 30}, {"Bar Chain Mail" ,0x00000000L, TV_HARD_ARMOR, '[',/*116*/ 0, 720, 6, 1, 280, -2, 0, 18, 0, {1,4} , 34}, {"Metal Brigandine Armor" ,0x00000000L, TV_HARD_ARMOR, '[',/*117*/ 0, 775, 7, 1, 290, -3, 0, 19, 0, {1,4} , 36}, {"Laminated Armor" ,0x00000000L, TV_HARD_ARMOR, '[',/*118*/ 0, 825, 8, 1, 300, -3, 0, 20, 0, {1,4} , 38}, {"Partial Plate Armor" ,0x00000000L, TV_HARD_ARMOR, '[',/*119*/ 0, 900, 9, 1, 320, -3, 0, 22, 0, {1,6} , 42}, {"Metal Lamellar Armor" ,0x00000000L, TV_HARD_ARMOR, '[',/*120*/ 0, 950, 10, 1, 340, -3, 0, 23, 0, {1,6} , 44}, {"Full Plate Armor" ,0x00000000L, TV_HARD_ARMOR, '[',/*121*/ 0, 1050, 11, 1, 380, -3, 0, 25, 0, {2,4} , 48}, {"Ribbed Plate Armor" ,0x00000000L, TV_HARD_ARMOR, '[',/*122*/ 0, 1200, 12, 1, 380, -3, 0, 28, 0, {2,4} , 50}, {"& Cloak" ,0x00000000L, TV_CLOAK, '(', /*123*/ 0, 3, 1, 1, 10, 0, 0, 1, 0, {0,0} , 1}, {"& Set of Leather Gloves" ,0x00000000L, TV_GLOVES, ']', /*124*/ 0, 3, 1, 1, 5, 0, 0, 1, 0, {0,0} , 1}, {"& Set of Gauntlets" ,0x00000000L, TV_GLOVES, ']', /*125*/ 0, 35, 2, 1, 25, 0, 0, 2, 0, {1,1} , 12}, {"& Small Leather Shield" ,0x00000000L, TV_SHIELD, ')', /*126*/ 0, 30, 1, 1, 50, 0, 0, 2, 0, {1,1} , 3}, {"& Medium Leather Shield" ,0x00000000L, TV_SHIELD, ')', /*127*/ 0, 60, 2, 1, 75, 0, 0, 3, 0, {1,2} , 8}, {"& Large Leather Shield" ,0x00000000L, TV_SHIELD, ')', /*128*/ 0, 120, 3, 1, 100, 0, 0, 4, 0, {1,2} , 15}, {"& Small Metal Shield" ,0x00000000L, TV_SHIELD, ')', /*129*/ 0, 50, 4, 1, 65, 0, 0, 3, 0, {1,2} , 10}, {"& Medium Metal Shield" ,0x00000000L, TV_SHIELD, ')', /*130*/ 0, 125, 5, 1, 90, 0, 0, 4, 0, {1,3} , 20}, {"& Large Metal Shield" ,0x00000000L, TV_SHIELD, ')', /*131*/ 0, 200, 6, 1, 120, 0, 0, 5, 0, {1,3} , 30}, {"Strength" ,0x00000001L, TV_RING, '=', /*132*/ 0, 400, 0, 1, 2, 0, 0, 0, 0, {0,0} , 30}, {"Dexterity" ,0x00000008L, TV_RING, '=', /*133*/ 0, 400, 1, 1, 2, 0, 0, 0, 0, {0,0} , 30}, {"Constitution" ,0x00000010L, TV_RING, '=', /*134*/ 0, 400, 2, 1, 2, 0, 0, 0, 0, {0,0} , 30}, {"Intelligence" ,0x00000002L, TV_RING, '=', /*135*/ 0, 400, 3, 1, 2, 0, 0, 0, 0, {0,0} , 30}, {"Speed" ,0x00001000L, TV_RING, '=', /*136*/ 0, 3000, 4, 1, 2, 0, 0, 0, 0, {0,0} , 50}, {"Searching" ,0x00000040L, TV_RING, '=', /*137*/ 0, 250, 5, 1, 2, 0, 0, 0, 0, {0,0} , 7}, {"Teleportation" ,0x80000400L, TV_RING, '=', /*138*/ 0, 0, 6, 1, 2, 0, 0, 0, 0, {0,0} , 7}, {"Slow Digestion" ,0x00000080L, TV_RING, '=', /*139*/ 0, 200, 7, 1, 2, 0, 0, 0, 0, {0,0} , 7}, {"Resist Fire" ,0x00080000L, TV_RING, '=', /*140*/ 0, 250, 8, 1, 2, 0, 0, 0, 0, {0,0} , 14}, {"Resist Cold" ,0x00200000L, TV_RING, '=', /*141*/ 0, 250, 9, 1, 2, 0, 0, 0, 0, {0,0} , 14}, {"Feather Falling" ,0x04000000L, TV_RING, '=', /*142*/ 0, 200, 10, 1, 2, 0, 0, 0, 0, {0,0} , 7}, {"Adornment" ,0x00000000L, TV_RING, '=', /*143*/ 0, 20, 11, 1, 2, 0, 0, 0, 0, {0,0} , 7}, /* was a ring of adornment, subval = 12 here */ {"& Arrow~" ,0x00000000L, TV_ARROW, '{', /*144*/ 0, 1, 193, 1, 2, 0, 0, 0, 0, {1,4} , 15}, {"Weakness" ,0x80000001L, TV_RING, '=', /*145*/ -5, 0, 13, 1, 2, 0, 0, 0, 0, {0,0} , 7}, {"Lordly Protection (FIRE)" ,0x00080000L, TV_RING, '=', /*146*/ 0, 1200, 14, 1, 2, 0, 0, 0, 5, {0,0} , 50}, {"Lordly Protection (ACID)" ,0x00100000L, TV_RING, '=', /*147*/ 0, 1200, 15, 1, 2, 0, 0, 0, 5, {0,0} , 50}, {"Lordly Protection (COLD)" ,0x00200000L, TV_RING, '=', /*148*/ 0, 1200, 16, 1, 2, 0, 0, 0, 5, {0,0} , 50}, {"WOE" ,0x80000644L, TV_RING, '=', /*149*/ -5, 0, 17, 1, 2, 0, 0, 0, -3, {0,0} , 50}, {"Stupidity" ,0x80000002L, TV_RING, '=', /*150*/ -5, 0, 18, 1, 2, 0, 0, 0, 0, {0,0} , 7}, {"Increase Damage" ,0x00000000L, TV_RING, '=', /*151*/ 0, 100, 19, 1, 2, 0, 0, 0, 0, {0,0} , 20}, {"Increase To-Hit" ,0x00000000L, TV_RING, '=', /*152*/ 0, 100, 20, 1, 2, 0, 0, 0, 0, {0,0} , 20}, {"Protection" ,0x00000000L, TV_RING, '=', /*153*/ 0, 100, 21, 1, 2, 0, 0, 0, 0, {0,0} , 7}, {"Aggravate Monster" ,0x80000200L, TV_RING, '=', /*154*/ 0, 0, 22, 1, 2, 0, 0, 0, 0, {0,0} , 7}, {"See Invisible" ,0x01000000L, TV_RING, '=', /*155*/ 0, 500, 23, 1, 2, 0, 0, 0, 0, {0,0} , 40}, {"Sustain Strength" ,0x00400000L, TV_RING, '=', /*156*/ 1, 750, 24, 1, 2, 0, 0, 0, 0, {0,0} , 44}, {"Sustain Intelligence" ,0x00400000L, TV_RING, '=', /*157*/ 2, 600, 25, 1, 2, 0, 0, 0, 0, {0,0} , 44}, {"Sustain Wisdom" ,0x00400000L, TV_RING, '=', /*158*/ 3, 600, 26, 1, 2, 0, 0, 0, 0, {0,0} , 44}, {"Sustain Constitution" ,0x00400000L, TV_RING, '=', /*159*/ 4, 750, 27, 1, 2, 0, 0, 0, 0, {0,0} , 44}, {"Sustain Dexterity" ,0x00400000L, TV_RING, '=', /*160*/ 5, 750, 28, 1, 2, 0, 0, 0, 0, {0,0} , 44}, {"Sustain Charisma" ,0x00400000L, TV_RING, '=', /*161*/ 6, 500, 29, 1, 2, 0, 0, 0, 0, {0,0} , 44}, {"Slaying" ,0x00000000L, TV_RING, '=', /*162*/ 0, 1000, 30, 1, 2, 0, 0, 0, 0, {0,0} , 50}, {"Wisdom" ,0x00000004L, TV_AMULET, '"', /*163*/ 0, 300, 0, 1, 3, 0, 0, 0, 0, {0,0} , 20}, {"Charisma" ,0x00000020L, TV_AMULET, '"', /*164*/ 0, 250, 1, 1, 3, 0, 0, 0, 0, {0,0} , 20}, {"Searching" ,0x00000040L, TV_AMULET, '"', /*165*/ 0, 250, 2, 1, 3, 0, 0, 0, 0, {0,0} , 14}, {"Teleportation" ,0x80000400L, TV_AMULET, '"', /*166*/ 0, 0, 3, 1, 3, 0, 0, 0, 0, {0,0} , 14}, {"Slow Digestion" ,0x00000080L, TV_AMULET, '"', /*167*/ 0, 200, 4, 1, 3, 0, 0, 0, 0, {0,0} , 14}, {"Resist Acid" ,0x00100000L, TV_AMULET, '"', /*168*/ 0, 250, 5, 1, 3, 0, 0, 0, 0, {0,0} , 24}, {"Adornment" ,0x00000000L, TV_AMULET, '"', /*169*/ 0, 20, 6, 1, 3, 0, 0, 0, 0, {0,0} , 16}, /* was an amulet of adornment here, subval = 7 */ {"& Bolt~" ,0x00000000L, TV_BOLT, '{', /*170*/ 0, 2, 193, 1, 3, 0, 0, 0, 0, {1,5} , 25}, {"the Magi" ,0x01800040L, TV_AMULET, '"', /*171*/ 0, 5000, 8, 1, 3, 0, 0, 0, 3, {0,0} , 50}, {"DOOM" ,0x8000007FL, TV_AMULET, '"', /*172*/ -5, 0, 9, 1, 3, 0, 0, 0, 0, {0,0} , 50}, {"Enchant Weapon To-Hit" ,0x00000001L, TV_SCROLL1, '?',/*173*/ 0, 125, 64, 1, 5, 0, 0, 0, 0, {0,0} , 12}, {"Enchant Weapon To-Dam" ,0x00000002L, TV_SCROLL1, '?',/*174*/ 0, 125, 65, 1, 5, 0, 0, 0, 0, {0,0} , 12}, {"Enchant Armor" ,0x00000004L, TV_SCROLL1, '?',/*175*/ 0, 125, 66, 1, 5, 0, 0, 0, 0, {0,0} , 12}, {"Identify" ,0x00000008L, TV_SCROLL1, '?',/*176*/ 0, 50, 67, 1, 5, 0, 0, 0, 0, {0,0} , 1}, {"Identify" ,0x00000008L, TV_SCROLL1, '?',/*177*/ 0, 50, 67, 1, 5, 0, 0, 0, 0, {0,0} , 5}, {"Identify" ,0x00000008L, TV_SCROLL1, '?',/*178*/ 0, 50, 67, 1, 5, 0, 0, 0, 0, {0,0} , 10}, {"Identify" ,0x00000008L, TV_SCROLL1, '?',/*179*/ 0, 50, 67, 1, 5, 0, 0, 0, 0, {0,0} , 30}, {"Remove Curse" ,0x00000010L, TV_SCROLL1, '?',/*180*/ 0, 100, 68, 1, 5, 0, 0, 0, 0, {0,0} , 7}, {"Light" ,0x00000020L, TV_SCROLL1, '?',/*181*/ 0, 15, 69, 1, 5, 0, 0, 0, 0, {0,0} , 0}, {"Light" ,0x00000020L, TV_SCROLL1, '?',/*182*/ 0, 15, 69, 1, 5, 0, 0, 0, 0, {0,0} , 3}, {"Light" ,0x00000020L, TV_SCROLL1, '?',/*183*/ 0, 15, 69, 1, 5, 0, 0, 0, 0, {0,0} , 7}, {"Summon Monster" ,0x00000040L, TV_SCROLL1, '?',/*184*/ 0, 0, 70, 1, 5, 0, 0, 0, 0, {0,0} , 1}, {"Phase Door" ,0x00000080L, TV_SCROLL1, '?',/*185*/ 0, 15, 71, 1, 5, 0, 0, 0, 0, {0,0} , 1}, {"Teleport" ,0x00000100L, TV_SCROLL1, '?',/*186*/ 0, 40, 72, 1, 5, 0, 0, 0, 0, {0,0} , 10}, {"Teleport Level" ,0x00000200L, TV_SCROLL1, '?',/*187*/ 0, 50, 73, 1, 5, 0, 0, 0, 0, {0,0} , 20}, {"Monster Confusion" ,0x00000400L, TV_SCROLL1, '?',/*188*/ 0, 30, 74, 1, 5, 0, 0, 0, 0, {0,0} , 5}, {"Magic Mapping" ,0x00000800L, TV_SCROLL1, '?',/*189*/ 0, 40, 75, 1, 5, 0, 0, 0, 0, {0,0} , 5}, {"Sleep Monster" ,0x00001000L, TV_SCROLL1, '?',/*190*/ 0, 35, 76, 1, 5, 0, 0, 0, 0, {0,0} , 5}, {"Rune of Protection" ,0x00002000L, TV_SCROLL1, '?',/*191*/ 0, 500, 77, 1, 5, 0, 0, 0, 0, {0,0} , 50}, {"Treasure Detection" ,0x00004000L, TV_SCROLL1, '?',/*192*/ 0, 15, 78, 1, 5, 0, 0, 0, 0, {0,0} , 0}, {"Object Detection" ,0x00008000L, TV_SCROLL1, '?',/*193*/ 0, 15, 79, 1, 5, 0, 0, 0, 0, {0,0} , 0}, {"Trap Detection" ,0x00010000L, TV_SCROLL1, '?',/*194*/ 0, 35, 80, 1, 5, 0, 0, 0, 0, {0,0} , 5}, {"Trap Detection" ,0x00010000L, TV_SCROLL1, '?',/*195*/ 0, 35, 80, 1, 5, 0, 0, 0, 0, {0,0} , 8}, {"Trap Detection" ,0x00010000L, TV_SCROLL1, '?',/*196*/ 0, 35, 80, 1, 5, 0, 0, 0, 0, {0,0} , 12}, {"Door/Stair Location" ,0x00020000L, TV_SCROLL1, '?',/*197*/ 0, 35, 81, 1, 5, 0, 0, 0, 0, {0,0} , 5}, {"Door/Stair Location" ,0x00020000L, TV_SCROLL1, '?',/*198*/ 0, 35, 81, 1, 5, 0, 0, 0, 0, {0,0} , 10}, {"Door/Stair Location" ,0x00020000L, TV_SCROLL1, '?',/*199*/ 0, 35, 81, 1, 5, 0, 0, 0, 0, {0,0} , 15}, {"Mass Genocide" ,0x00040000L, TV_SCROLL1, '?',/*200*/ 0, 1000, 82, 1, 5, 0, 0, 0, 0, {0,0} , 50}, {"Detect Invisible" ,0x00080000L, TV_SCROLL1, '?',/*201*/ 0, 15, 83, 1, 5, 0, 0, 0, 0, {0,0} , 1}, {"Aggravate Monster" ,0x00100000L, TV_SCROLL1, '?',/*202*/ 0, 0, 84, 1, 5, 0, 0, 0, 0, {0,0} , 5}, {"Trap Creation" ,0x00200000L, TV_SCROLL1, '?',/*203*/ 0, 0, 85, 1, 5, 0, 0, 0, 0, {0,0} , 12}, {"Trap/Door Destruction" ,0x00400000L, TV_SCROLL1, '?',/*204*/ 0, 50, 86, 1, 5, 0, 0, 0, 0, {0,0} , 12}, {"Door Creation" ,0x00800000L, TV_SCROLL1, '?',/*205*/ 0, 100, 87, 1, 5, 0, 0, 0, 0, {0,0} , 12}, {"Recharging" ,0x01000000L, TV_SCROLL1, '?',/*206*/ 0, 200, 88, 1, 5, 0, 0, 0, 0, {0,0} , 40}, {"Genocide" ,0x02000000L, TV_SCROLL1, '?',/*207*/ 0, 750, 89, 1, 5, 0, 0, 0, 0, {0,0} , 35}, {"Darkness" ,0x04000000L, TV_SCROLL1, '?',/*208*/ 0, 0, 90, 1, 5, 0, 0, 0, 0, {0,0} , 1}, {"Protection from Evil" ,0x08000000L, TV_SCROLL1, '?',/*209*/ 0, 100, 91, 1, 5, 0, 0, 0, 0, {0,0} , 30}, {"Create Food" ,0x10000000L, TV_SCROLL1, '?',/*210*/ 0, 10, 92, 1, 5, 0, 0, 0, 0, {0,0} , 5}, {"Dispel Undead" ,0x20000000L, TV_SCROLL1, '?',/*211*/ 0, 200, 93, 1, 5, 0, 0, 0, 0, {0,0} , 40}, {"*Enchant Weapon*" ,0x00000001L, TV_SCROLL2, '?',/*212*/ 0, 500, 94, 1, 5, 0, 0, 0, 0, {0,0} , 50}, {"Curse Weapon" ,0x00000002L, TV_SCROLL2, '?',/*213*/ 0, 0, 95, 1, 5, 0, 0, 0, 0, {0,0} , 50}, {"*Enchant Armor*" ,0x00000004L, TV_SCROLL2, '?',/*214*/ 0, 500, 96, 1, 5, 0, 0, 0, 0, {0,0} , 50}, {"Curse Armor" ,0x00000008L, TV_SCROLL2, '?',/*215*/ 0, 0, 97, 1, 5, 0, 0, 0, 0, {0,0} , 50}, {"Summon Undead" ,0x00000010L, TV_SCROLL2, '?',/*216*/ 0, 0, 98, 1, 5, 0, 0, 0, 0, {0,0} , 15}, {"Blessing" ,0x00000020L, TV_SCROLL2, '?',/*217*/ 0, 15, 99, 1, 5, 0, 0, 0, 0, {0,0} , 1}, {"Holy Chant" ,0x00000040L, TV_SCROLL2, '?',/*218*/ 0, 40, 100, 1, 5, 0, 0, 0, 0, {0,0} , 12}, {"Holy Prayer" ,0x00000080L, TV_SCROLL2, '?',/*219*/ 0, 80, 101, 1, 5, 0, 0, 0, 0, {0,0} , 24}, {"Word-of-Recall" ,0x00000100L, TV_SCROLL2, '?',/*220*/ 0, 150, 102, 1, 5, 0, 0, 0, 0, {0,0} , 5}, {"*Destruction*" ,0x00000200L, TV_SCROLL2, '?',/*221*/ 0, 750, 103, 1, 5, 0, 0, 0, 0, {0,0} , 40}, /* SMJ, AJ, Water must be subval 64-66 resp. for objdes to work */ {"Slime Mold Juice" ,0x30000000L, TV_POTION1, '!',/*222*/ 400, 2, 64, 1, 4, 0, 0, 0, 0, {1,1} , 0}, {"Apple Juice" ,0x00000000L, TV_POTION1, '!',/*223*/ 250, 1, 65, 1, 4, 0, 0, 0, 0, {1,1} , 0}, {"Water" ,0x00000000L, TV_POTION1, '!',/*224*/ 200, 0, 66, 1, 4, 0, 0, 0, 0, {1,1} , 0}, {"Strength" ,0x00000001L, TV_POTION1, '!',/*225*/ 50, 300, 67, 1, 4, 0, 0, 0, 0, {1,1} , 25}, {"Weakness" ,0x00000002L, TV_POTION1, '!',/*226*/ 0, 0, 68, 1, 4, 0, 0, 0, 0, {1,1} , 3}, {"Restore Strength" ,0x00000004L, TV_POTION1, '!',/*227*/ 0, 300, 69, 1, 4, 0, 0, 0, 0, {1,1} , 40}, {"Intelligence" ,0x00000008L, TV_POTION1, '!',/*228*/ 0, 300, 70, 1, 4, 0, 0, 0, 0, {1,1} , 25}, {"Lose Intelligence" ,0x00000010L, TV_POTION1, '!',/*229*/ 0, 0, 71, 1, 4, 0, 0, 0, 0, {1,1} , 25}, {"Restore Intelligence" ,0x00000020L, TV_POTION1, '!',/*230*/ 0, 300, 72, 1, 4, 0, 0, 0, 0, {1,1} , 40}, {"Wisdom" ,0x00000040L, TV_POTION1, '!',/*231*/ 0, 300, 73, 1, 4, 0, 0, 0, 0, {1,1} , 25}, {"Lose Wisdom" ,0x00000080L, TV_POTION1, '!',/*232*/ 0, 0, 74, 1, 4, 0, 0, 0, 0, {1,1} , 25}, {"Restore Wisdom" ,0x00000100L, TV_POTION1, '!',/*233*/ 0, 300, 75, 1, 4, 0, 0, 0, 0, {1,1} , 40}, {"Charisma" ,0x00000200L, TV_POTION1, '!',/*234*/ 0, 300, 76, 1, 4, 0, 0, 0, 0, {1,1} , 25}, {"Ugliness" ,0x00000400L, TV_POTION1, '!',/*235*/ 0, 0, 77, 1, 4, 0, 0, 0, 0, {1,1} , 25}, {"Restore Charisma" ,0x00000800L, TV_POTION1, '!',/*236*/ 0, 300, 78, 1, 4, 0, 0, 0, 0, {1,1} , 40}, {"Cure Light Wounds" ,0x10001000L, TV_POTION1, '!',/*237*/ 50, 15, 79, 1, 4, 0, 0, 0, 0, {1,1} , 0}, {"Cure Light Wounds" ,0x10001000L, TV_POTION1, '!',/*238*/ 50, 15, 79, 1, 4, 0, 0, 0, 0, {1,1} , 1}, {"Cure Light Wounds" ,0x10001000L, TV_POTION1, '!',/*239*/ 50, 15, 79, 1, 4, 0, 0, 0, 0, {1,1} , 2}, {"Cure Serious Wounds" ,0x30002000L, TV_POTION1, '!',/*240*/ 100, 40, 80, 1, 4, 0, 0, 0, 0, {1,1} , 3}, {"Cure Critical Wounds" ,0x70004000L, TV_POTION1, '!',/*241*/ 100, 100, 81, 1, 4, 0, 0, 0, 0, {1,1} , 5}, {"Healing" ,0x70008000L, TV_POTION1, '!',/*242*/ 200, 200, 82, 1, 4, 0, 0, 0, 0, {1,1} , 12}, {"Constitution" ,0x00010000L, TV_POTION1, '!',/*243*/ 50, 300, 83, 1, 4, 0, 0, 0, 0, {1,1} , 25}, {"Gain Experience" ,0x00020000L, TV_POTION1, '!',/*244*/ 0, 2500, 84, 1, 4, 0, 0, 0, 0, {1,1} , 50}, {"Sleep" ,0x00040000L, TV_POTION1, '!',/*245*/ 100, 0, 85, 1, 4, 0, 0, 0, 0, {1,1} , 0}, {"Blindness" ,0x00080000L, TV_POTION1, '!',/*246*/ 0, 0, 86, 1, 4, 0, 0, 0, 0, {1,1} , 0}, {"Confusion" ,0x00100000L, TV_POTION1, '!',/*247*/ 50, 0, 87, 1, 4, 0, 0, 0, 0, {1,1} , 0}, {"Poison" ,0x00200000L, TV_POTION1, '!',/*248*/ 0, 0, 88, 1, 4, 0, 0, 0, 0, {1,1} , 3}, {"Haste Self" ,0x00400000L, TV_POTION1, '!',/*249*/ 0, 75, 89, 1, 4, 0, 0, 0, 0, {1,1} , 1}, {"Slowness" ,0x00800000L, TV_POTION1, '!',/*250*/ 50, 0, 90, 1, 4, 0, 0, 0, 0, {1,1} , 1}, {"Dexterity" ,0x02000000L, TV_POTION1, '!',/*251*/ 0, 300, 91, 1, 4, 0, 0, 0, 0, {1,1} , 25}, {"Restore Dexterity" ,0x04000000L, TV_POTION1, '!',/*252*/ 0, 300, 92, 1, 4, 0, 0, 0, 0, {1,1} , 40}, {"Restore Constitution" ,0x68000000L, TV_POTION1, '!',/*253*/ 0, 300, 93, 1, 4, 0, 0, 0, 0, {1,1} , 40}, {"Lose Experience" ,0x00000002L, TV_POTION2, '!',/*254*/ 0, 0, 95, 1, 4, 0, 0, 0, 0, {1,1} , 10}, {"Salt Water" ,0x00000004L, TV_POTION2, '!',/*255*/ 0, 0, 96, 1, 4, 0, 0, 0, 0, {1,1} , 0}, {"Invulnerability" ,0x00000008L, TV_POTION2, '!',/*256*/ 0, 1000, 97, 1, 4, 0, 0, 0, 0, {1,1} , 40}, {"Heroism" ,0x00000010L, TV_POTION2, '!',/*257*/ 0, 35, 98, 1, 4, 0, 0, 0, 0, {1,1} , 1}, {"Super Heroism" ,0x00000020L, TV_POTION2, '!',/*258*/ 0, 100, 99, 1, 4, 0, 0, 0, 0, {1,1} , 3}, {"Boldness" ,0x00000040L, TV_POTION2, '!',/*259*/ 0, 10, 100, 1, 4, 0, 0, 0, 0, {1,1} , 1}, {"Restore Life Levels" ,0x00000080L, TV_POTION2, '!',/*260*/ 0, 400, 101, 1, 4, 0, 0, 0, 0, {1,1} , 40}, {"Resist Heat" ,0x00000100L, TV_POTION2, '!',/*261*/ 0, 30, 102, 1, 4, 0, 0, 0, 0, {1,1} , 1}, {"Resist Cold" ,0x00000200L, TV_POTION2, '!',/*262*/ 0, 30, 103, 1, 4, 0, 0, 0, 0, {1,1} , 1}, {"Detect Invisible" ,0x00000400L, TV_POTION2, '!',/*263*/ 0, 50, 104, 1, 4, 0, 0, 0, 0, {1,1} , 3}, {"Slow Poison" ,0x00000800L, TV_POTION2, '!',/*264*/ 0, 25, 105, 1, 4, 0, 0, 0, 0, {1,1} , 1}, {"Neutralize Poison" ,0x00001000L, TV_POTION2, '!',/*265*/ 0, 75, 106, 1, 4, 0, 0, 0, 0, {1,1} , 5}, {"Restore Mana" ,0x00002000L, TV_POTION2, '!',/*266*/ 0, 350, 107, 1, 4, 0, 0, 0, 0, {1,1} , 25}, {"Infra-Vision" ,0x00004000L, TV_POTION2, '!',/*267*/ 0, 20, 108, 1, 4, 0, 0, 0, 0, {1,1} , 3}, {"& Flask~ of Oil" ,0x00040000L, TV_FLASK, '!', /*268*/ 7500, 3, 64, 1, 10, 0, 0, 0, 0, {2,6} , 1}, {"Light" ,0x00000001L, TV_WAND, '-', /*269*/ 0, 200, 0, 1, 10, 0, 0, 0, 0, {1,1} , 2}, {"Lightning Bolts" ,0x00000002L, TV_WAND, '-', /*270*/ 0, 600, 1, 1, 10, 0, 0, 0, 0, {1,1} , 15}, {"Frost Bolts" ,0x00000004L, TV_WAND, '-', /*271*/ 0, 800, 2, 1, 10, 0, 0, 0, 0, {1,1} , 20}, {"Fire Bolts" ,0x00000008L, TV_WAND, '-', /*272*/ 0, 1000, 3, 1, 10, 0, 0, 0, 0, {1,1} , 30}, {"Stone-to-Mud" ,0x00000010L, TV_WAND, '-', /*273*/ 0, 300, 4, 1, 10, 0, 0, 0, 0, {1,1} , 12}, {"Polymorph" ,0x00000020L, TV_WAND, '-', /*274*/ 0, 400, 5, 1, 10, 0, 0, 0, 0, {1,1} , 20}, {"Heal Monster" ,0x00000040L, TV_WAND, '-', /*275*/ 0, 0, 6, 1, 10, 0, 0, 0, 0, {1,1} , 2}, {"Haste Monster" ,0x00000080L, TV_WAND, '-', /*276*/ 0, 0, 7, 1, 10, 0, 0, 0, 0, {1,1} , 2}, {"Slow Monster" ,0x00000100L, TV_WAND, '-', /*277*/ 0, 500, 8, 1, 10, 0, 0, 0, 0, {1,1} , 2}, {"Confuse Monster" ,0x00000200L, TV_WAND, '-', /*278*/ 0, 400, 9, 1, 10, 0, 0, 0, 0, {1,1} , 2}, {"Sleep Monster" ,0x00000400L, TV_WAND, '-', /*279*/ 0, 500, 10, 1, 10, 0, 0, 0, 0, {1,1} , 7}, {"Drain Life" ,0x00000800L, TV_WAND, '-', /*280*/ 0, 1200, 11, 1, 10, 0, 0, 0, 0, {1,1} , 50}, {"Trap/Door Destruction" ,0x00001000L, TV_WAND, '-', /*281*/ 0, 500, 12, 1, 10, 0, 0, 0, 0, {1,1} , 12}, {"Magic Missile" ,0x00002000L, TV_WAND, '-', /*282*/ 0, 200, 13, 1, 10, 0, 0, 0, 0, {1,1} , 2}, {"Wall Building" ,0x00004000L, TV_WAND, '-', /*283*/ 0, 400, 14, 1, 10, 0, 0, 0, 0, {1,1} , 25}, {"Clone Monster" ,0x00008000L, TV_WAND, '-', /*284*/ 0, 0, 15, 1, 10, 0, 0, 0, 0, {1,1} , 15}, {"Teleport Away" ,0x00010000L, TV_WAND, '-', /*285*/ 0, 350, 16, 1, 10, 0, 0, 0, 0, {1,1} , 20}, {"Disarming" ,0x00020000L, TV_WAND, '-', /*286*/ 0, 500, 17, 1, 10, 0, 0, 0, 0, {1,1} , 20}, {"Lightning Balls" ,0x00040000L, TV_WAND, '-', /*287*/ 0, 1200, 18, 1, 10, 0, 0, 0, 0, {1,1} , 35}, {"Cold Balls" ,0x00080000L, TV_WAND, '-', /*288*/ 0, 1500, 19, 1, 10, 0, 0, 0, 0, {1,1} , 40}, {"Fire Balls" ,0x00100000L, TV_WAND, '-', /*289*/ 0, 1800, 20, 1, 10, 0, 0, 0, 0, {1,1} , 50}, {"Stinking Cloud" ,0x00200000L, TV_WAND, '-', /*290*/ 0, 400, 21, 1, 10, 0, 0, 0, 0, {1,1} , 5}, {"Acid Balls" ,0x00400000L, TV_WAND, '-', /*291*/ 0, 1650, 22, 1, 10, 0, 0, 0, 0, {1,1} , 48}, {"Wonder" ,0x00800000L, TV_WAND, '-', /*292*/ 0, 250, 23, 1, 10, 0, 0, 0, 0, {1,1} , 2}, {"Light" ,0x00000001L, TV_STAFF, '_', /*293*/ 0, 250, 0, 1, 50, 0, 0, 0, 0, {1,2} , 5}, {"Door/Stair Location" ,0x00000002L, TV_STAFF, '_', /*294*/ 0, 350, 1, 1, 50, 0, 0, 0, 0, {1,2} , 10}, {"Trap Location" ,0x00000004L, TV_STAFF, '_', /*295*/ 0, 350, 2, 1, 50, 0, 0, 0, 0, {1,2} , 10}, {"Treasure Location" ,0x00000008L, TV_STAFF, '_', /*296*/ 0, 200, 3, 1, 50, 0, 0, 0, 0, {1,2} , 5}, {"Object Location" ,0x00000010L, TV_STAFF, '_', /*297*/ 0, 200, 4, 1, 50, 0, 0, 0, 0, {1,2} , 5}, {"Teleportation" ,0x00000020L, TV_STAFF, '_', /*298*/ 0, 800, 5, 1, 50, 0, 0, 0, 0, {1,2} , 20}, {"Earthquakes" ,0x00000040L, TV_STAFF, '_', /*299*/ 0, 350, 6, 1, 50, 0, 0, 0, 0, {1,2} , 40}, {"Summoning" ,0x00000080L, TV_STAFF, '_', /*300*/ 0, 0, 7, 1, 50, 0, 0, 0, 0, {1,2} , 10}, {"Summoning" ,0x00000080L, TV_STAFF, '_', /*301*/ 0, 0, 7, 1, 50, 0, 0, 0, 0, {1,2} , 50}, {"*Destruction*" ,0x00000200L, TV_STAFF, '_', /*302*/ 0, 2500, 8, 1, 50, 0, 0, 0, 0, {1,2} , 50}, {"Starlight" ,0x00000400L, TV_STAFF, '_', /*303*/ 0, 400, 9, 1, 50, 0, 0, 0, 0, {1,2} , 20}, {"Haste Monsters" ,0x00000800L, TV_STAFF, '_', /*304*/ 0, 0, 10, 1, 50, 0, 0, 0, 0, {1,2} , 10}, {"Slow Monsters" ,0x00001000L, TV_STAFF, '_', /*305*/ 0, 800, 11, 1, 50, 0, 0, 0, 0, {1,2} , 10}, {"Sleep Monsters" ,0x00002000L, TV_STAFF, '_', /*306*/ 0, 700, 12, 1, 50, 0, 0, 0, 0, {1,2} , 10}, {"Cure Light Wounds" ,0x00004000L, TV_STAFF, '_', /*307*/ 0, 200, 13, 1, 50, 0, 0, 0, 0, {1,2} , 5}, {"Detect Invisible" ,0x00008000L, TV_STAFF, '_', /*308*/ 0, 200, 14, 1, 50, 0, 0, 0, 0, {1,2} , 5}, {"Speed" ,0x00010000L, TV_STAFF, '_', /*309*/ 0, 1000, 15, 1, 50, 0, 0, 0, 0, {1,2} , 40}, {"Slowness" ,0x00020000L, TV_STAFF, '_', /*310*/ 0, 0, 16, 1, 50, 0, 0, 0, 0, {1,2} , 40}, {"Mass Polymorph" ,0x00040000L, TV_STAFF, '_', /*311*/ 0, 750, 17, 1, 50, 0, 0, 0, 0, {1,2} , 46}, {"Remove Curse" ,0x00080000L, TV_STAFF, '_', /*312*/ 0, 500, 18, 1, 50, 0, 0, 0, 0, {1,2} , 47}, {"Detect Evil" ,0x00100000L, TV_STAFF, '_', /*313*/ 0, 350, 19, 1, 50, 0, 0, 0, 0, {1,2} , 20}, {"Curing" ,0x00200000L, TV_STAFF, '_', /*314*/ 0, 1000, 20, 1, 50, 0, 0, 0, 0, {1,2} , 25}, {"Dispel Evil" ,0x00400000L, TV_STAFF, '_', /*315*/ 0, 1200, 21, 1, 50, 0, 0, 0, 0, {1,2} , 49}, {"Darkness" ,0x01000000L, TV_STAFF, '_', /*316*/ 0, 0, 22, 1, 50, 0, 0, 0, 0, {1,2} , 50}, {"Darkness" ,0x01000000L, TV_STAFF, '_', /*317*/ 0, 0, 22, 1, 50, 0, 0, 0, 0, {1,2} , 5}, {"[Beginners-Magick]" ,0x0000007FL, TV_MAGIC_BOOK, '?',/*318*/ 0, 25, 64, 1, 30, 0, 0, 0, 0, {1,1} , 40}, {"[Magick I]" ,0x0000FF80L, TV_MAGIC_BOOK, '?',/*319*/ 0, 100, 65, 1, 30, 0, 0, 0, 0, {1,1} , 40}, {"[Magick II]" ,0x00FF0000L, TV_MAGIC_BOOK, '?',/*320*/ 0, 400, 66, 1, 30, 0, 0, 0, 0, {1,1} , 40}, {"[The Mages' Guide to Power]" ,0x7F000000L, TV_MAGIC_BOOK, '?',/*321*/ 0, 800, 67, 1, 30, 0, 0, 0, 0, {1,1} , 40}, {"[Beginners Handbook]" ,0x000000FFL, TV_PRAYER_BOOK, '?',/*322*/ 0, 25, 64, 1, 30, 0, 0, 0, 0, {1,1} , 40}, {"[Words of Wisdom]" ,0x0000FF00L, TV_PRAYER_BOOK, '?',/*323*/ 0, 100, 65, 1, 30, 0, 0, 0, 0, {1,1} , 40}, {"[Chants and Blessings]" ,0x01FF0000L, TV_PRAYER_BOOK, '?',/*324*/ 0, 400, 66, 1, 30, 0, 0, 0, 0, {1,1} , 40}, {"[Exorcisms and Dispellings]" ,0x7E000000L, TV_PRAYER_BOOK, '?',/*325*/ 0, 800, 67, 1, 30, 0, 0, 0, 0, {1,1} , 40}, {"& Small Wooden Chest" ,0x13800000L, TV_CHEST, '&', /*326*/ 0, 20, 1, 1, 250, 0, 0, 0, 0, {2,3} , 7}, {"& Large Wooden Chest" ,0x17800000L, TV_CHEST, '&', /*327*/ 0, 60, 4, 1, 500, 0, 0, 0, 0, {2,5} , 15}, {"& Small Iron Chest" ,0x17800000L, TV_CHEST, '&', /*328*/ 0, 100, 7, 1, 500, 0, 0, 0, 0, {2,4} , 25}, {"& Large Iron Chest" ,0x23800000L, TV_CHEST, '&', /*329*/ 0, 150, 10, 1,1000, 0, 0, 0, 0, {2,6} , 35}, {"& Small Steel Chest" ,0x1B800000L, TV_CHEST, '&', /*330*/ 0, 200, 13, 1, 500, 0, 0, 0, 0, {2,4} , 45}, {"& Large Steel Chest" ,0x33800000L, TV_CHEST, '&', /*331*/ 0, 250, 16, 1,1000, 0, 0, 0, 0, {2,6} , 50}, {"& Rat Skeleton" ,0x00000000L, TV_MISC, 's', /*332*/ 0, 0, 1, 1, 10, 0, 0, 0, 0, {1,1} , 1}, {"& Giant Centipede Skeleton" ,0x00000000L, TV_MISC, 's', /*333*/ 0, 0, 2, 1, 25, 0, 0, 0, 0, {1,1} , 1}, {"some Filthy Rags" ,0x00000000L, TV_SOFT_ARMOR, '~',/*334*/ 0, 0, 63, 1, 20, 0, 0, 1, 0, {0,0} , 0}, {"& empty bottle" ,0x00000000L, TV_MISC, '!', /*335*/ 0, 0, 4, 1, 2, 0, 0, 0, 0, {1,1} , 0}, {"some shards of pottery" ,0x00000000L, TV_MISC, '~', /*336*/ 0, 0, 5, 1, 5, 0, 0, 0, 0, {1,1} , 0}, {"& Human Skeleton" ,0x00000000L, TV_MISC, 's', /*337*/ 0, 0, 7, 1, 60, 0, 0, 0, 0, {1,1} , 1}, {"& Dwarf Skeleton" ,0x00000000L, TV_MISC, 's', /*338*/ 0, 0, 8, 1, 50, 0, 0, 0, 0, {1,1} , 1}, {"& Elf Skeleton" ,0x00000000L, TV_MISC, 's', /*339*/ 0, 0, 9, 1, 40, 0, 0, 0, 0, {1,1} , 1}, {"& Gnome Skeleton" ,0x00000000L, TV_MISC, 's', /*340*/ 0, 0, 10, 1, 25, 0, 0, 0, 0, {1,1} , 1}, {"& broken set of teeth" ,0x00000000L, TV_MISC, 's', /*341*/ 0, 0, 11, 1, 3, 0, 0, 0, 0, {1,1} , 0}, {"& large broken bone" ,0x00000000L, TV_MISC, 's', /*342*/ 0, 0, 12, 1, 2, 0, 0, 0, 0, {1,1} , 0}, {"& broken stick" ,0x00000000L, TV_MISC, '~', /*343*/ 0, 0, 13, 1, 3, 0, 0, 0, 0, {1,1} , 0}, /* end of Dungeon items */ /* Store items, which are not also dungeon items, some of these can be found above, except that the number is >1 below */ {"& Ration~ of Food" ,0x00000000L, TV_FOOD, ',', /*344*/ 5000, 3, 90, 5, 10, 0, 0, 0, 0, {0,0} , 0}, {"& Hard Biscuit~" ,0x00000000L, TV_FOOD, ',', /*345*/ 500, 1, 93, 5, 2, 0, 0, 0, 0, {0,0} , 0}, {"& Strip~ of Beef Jerky" ,0x00000000L, TV_FOOD, ',', /*346*/ 1750, 2, 94, 5, 4, 0, 0, 0, 0, {0,0} , 0}, {"& Pint~ of Fine Ale" ,0x00000000L, TV_FOOD, ',', /*347*/ 500, 1, 95, 3, 10, 0, 0, 0, 0, {0,0} , 0}, {"& Pint~ of Fine Wine" ,0x00000000L, TV_FOOD, ',', /*348*/ 400, 2, 96, 1, 10, 0, 0, 0, 0, {0,0} , 0}, {"& Pick" ,0x20000000L, TV_DIGGING, '\\',/*349*/ 1, 50, 1, 1, 150, 0, 0, 0, 0, {1,3} , 0}, {"& Shovel" ,0x20000000L, TV_DIGGING, '\\',/*350*/ 0, 15, 4, 1, 60, 0, 0, 0, 0, {1,2} , 0}, {"Identify" ,0x00000008L, TV_SCROLL1, '?',/*351*/ 0, 50, 67, 2, 5, 0, 0, 0, 0, {0,0} , 0}, {"Light" ,0x00000020L, TV_SCROLL1, '?',/*352*/ 0, 15, 69, 3, 5, 0, 0, 0, 0, {0,0} , 0}, {"Phase Door" ,0x00000080L, TV_SCROLL1, '?',/*353*/ 0, 15, 71, 2, 5, 0, 0, 0, 0, {0,0} , 0}, {"Magic Mapping" ,0x00000800L, TV_SCROLL1, '?',/*354*/ 0, 40, 75, 2, 5, 0, 0, 0, 0, {0,0} , 0}, {"Treasure Detection" ,0x00004000L, TV_SCROLL1, '?',/*355*/ 0, 15, 78, 2, 5, 0, 0, 0, 0, {0,0} , 0}, {"Object Detection" ,0x00008000L, TV_SCROLL1, '?',/*356*/ 0, 15, 79, 2, 5, 0, 0, 0, 0, {0,0} , 0}, {"Detect Invisible" ,0x00080000L, TV_SCROLL1, '?',/*357*/ 0, 15, 83, 2, 5, 0, 0, 0, 0, {0,0} , 0}, {"Blessing" ,0x00000020L, TV_SCROLL2, '?',/*358*/ 0, 15, 99, 2, 5, 0, 0, 0, 0, {0,0} , 0}, {"Word-of-Recall" ,0x00000100L, TV_SCROLL2, '?',/*359*/ 0, 150, 102, 3, 5, 0, 0, 0, 0, {0,0} , 0}, {"Cure Light Wounds" ,0x10001000L, TV_POTION1, '!',/*360*/ 50, 15, 79, 2, 4, 0, 0, 0, 0, {1,1} , 0}, {"Heroism" ,0x00000010L, TV_POTION2, '!',/*361*/ 0, 35, 98, 2, 4, 0, 0, 0, 0, {1,1} , 0}, {"Boldness" ,0x00000040L, TV_POTION2, '!',/*362*/ 0, 10, 100, 2, 4, 0, 0, 0, 0, {1,1} , 0}, {"Slow Poison" ,0x00000800L, TV_POTION2, '!',/*363*/ 0, 25, 105, 2, 4, 0, 0, 0, 0, {1,1} , 0}, {"& Brass Lantern~" ,0x00000000L, TV_LIGHT, '~', /*364*/ 7500, 35, 0, 1, 50, 0, 0, 0, 0, {1,1} , 1}, {"& Wooden Torch~" ,0x00000000L, TV_LIGHT, '~', /*365*/ 4000, 2, 192, 5, 30, 0, 0, 0, 0, {1,1} , 1}, {"& Flask~ of Oil" ,0x00040000L, TV_FLASK, '!', /*366*/ 7500, 3, 64, 5, 10, 0, 0, 0, 0, {2,6} , 1}, /* end store items */ /* start doors */ /* Secret door must have same subval as closed door in */ /* TRAP_LISTB. See CHANGE_TRAP. Must use & because of stone_to_mud. */ {"& open door" ,0x00000000L, TV_OPEN_DOOR, '\'', 0, 0, 1, 1, 0, 0, 0, 0, 0, {1,1} , 0}, {"& closed door" ,0x00000000L, TV_CLOSED_DOOR, '+', 0, 0, 19, 1, 0, 0, 0, 0, 0, {1,1} , 0}, #ifdef ATARI_ST {"& secret door" ,0x00000000L, TV_SECRET_DOOR, (unsigned char)240, /* 369 */ #else {"& secret door" ,0x00000000L, TV_SECRET_DOOR, '#',/* 369 */ #endif 0, 0, 19, 1, 0, 0, 0, 0, 0, {1,1} , 0}, /* end doors */ /* stairs */ {"an up staircase" ,0x00000000L, TV_UP_STAIR, '<', /* 370 */ 0, 0, 1, 1, 0, 0, 0, 0, 0, {1,1} , 0}, {"a down staircase" ,0x00000000L, TV_DOWN_STAIR, '>',/* 371 */ 0, 0, 1, 1, 0, 0, 0, 0, 0, {1,1} , 0}, /* store door */ /* Stores are just special traps */ {"General Store" ,0x00000000L, TV_STORE_DOOR, '1',/* 372 */ 0, 0, 101, 1, 0, 0, 0, 0, 0, {0,0} , 0}, {"Armory" ,0x00000000L, TV_STORE_DOOR, '2', 0, 0, 102, 1, 0, 0, 0, 0, 0, {0,0} , 0}, {"Weapon Smiths" ,0x00000000L, TV_STORE_DOOR, '3', 0, 0, 103, 1, 0, 0, 0, 0, 0, {0,0} , 0}, {"Temple" ,0x00000000L, TV_STORE_DOOR, '4', 0, 0, 104, 1, 0, 0, 0, 0, 0, {0,0} , 0}, {"Alchemy Shop" ,0x00000000L, TV_STORE_DOOR, '5', 0, 0, 105, 1, 0, 0, 0, 0, 0, {0,0} , 0}, {"Magic Shop" ,0x00000000L, TV_STORE_DOOR, '6',/* 377 */ 0, 0, 106, 1, 0, 0, 0, 0, 0, {0,0} , 0}, /* end store door */ /* Traps are just Nasty treasures. */ /* Traps: Level represents the relative difficulty of disarming; */ /* and P1 represents the experienced gained when disarmed*/ {"an open pit" ,0x00000000L, TV_VIS_TRAP, ' ', /* 378 */ 1, 0, 1, 1, 0, 0, 0, 0, 0, {2,6} ,50}, {"an arrow trap" ,0x00000000L, TV_INVIS_TRAP, '^', 3, 0, 2, 1, 0, 0, 0, 0, 0, {1,8} ,90}, {"a covered pit" ,0x00000000L, TV_INVIS_TRAP, '^', 2, 0, 3, 1, 0, 0, 0, 0, 0, {2,6} ,60}, {"a trap door" ,0x00000000L, TV_INVIS_TRAP, '^', 5, 0, 4, 1, 0, 0, 0, 0, 0, {2,8} ,75}, {"a gas trap" ,0x00000000L, TV_INVIS_TRAP, '^', 3, 0, 5, 1, 0, 0, 0, 0, 0, {1,4} ,95}, {"a loose rock" ,0x00000000L, TV_INVIS_TRAP, ';', 0, 0, 6, 1, 0, 0, 0, 0, 0, {0,0} ,10}, {"a dart trap" ,0x00000000L, TV_INVIS_TRAP, '^', 5, 0, 7, 1, 0, 0, 0, 0, 0, {1,4} ,110}, {"a strange rune" ,0x00000000L, TV_INVIS_TRAP, '^', 5, 0, 8, 1, 0, 0, 0, 0, 0, {0,0} ,90}, {"some loose rock" ,0x00000000L, TV_INVIS_TRAP, '^', 5, 0, 9, 1, 0, 0, 0, 0, 0, {2,6} ,90}, {"a gas trap" ,0x00000000L, TV_INVIS_TRAP, '^', 10, 0, 10, 1, 0, 0, 0, 0, 0, {1,4} ,105}, {"a strange rune" ,0x00000000L, TV_INVIS_TRAP, '^', 5, 0, 11, 1, 0, 0, 0, 0, 0, {0,0} ,90}, {"a blackened spot" ,0x00000000L, TV_INVIS_TRAP, '^', 10, 0, 12, 1, 0, 0, 0, 0, 0, {4,6} ,110}, {"some corroded rock" ,0x00000000L, TV_INVIS_TRAP, '^', 10, 0, 13, 1, 0, 0, 0, 0, 0, {4,6} ,110}, {"a gas trap" ,0x00000000L, TV_INVIS_TRAP, '^', 5, 0, 14, 1, 0, 0, 0, 0, 0, {2,6} ,105}, {"a gas trap" ,0x00000000L, TV_INVIS_TRAP, '^', 5, 0, 15, 1, 0, 0, 0, 0, 0, {1,4} ,110}, {"a gas trap" ,0x00000000L, TV_INVIS_TRAP, '^', 5, 0, 16, 1, 0, 0, 0, 0, 0, {1,8} ,105}, {"a dart trap" ,0x00000000L, TV_INVIS_TRAP, '^', 5, 0, 17, 1, 0, 0, 0, 0, 0, {1,8} ,110}, {"a dart trap" ,0x00000000L, TV_INVIS_TRAP, '^',/* 395 */ 5, 0, 18, 1, 0, 0, 0, 0, 0, {1,8} ,110}, /* rubble */ {"some rubble" ,0x00000000L, TV_RUBBLE, ':', /* 396 */ 0, 0, 1, 1, 0, 0, 0, 0, 0, {0,0} , 0}, /* mush */ {"& Pint~ of Fine Grade Mush" ,0x00000000L, TV_FOOD, ',', /* 397 */ 1500, 1, 97, 1, 1, 0, 0, 0, 0, {1,1} , 1}, /* Special trap */ {"a strange rune" ,0x00000000L, TV_VIS_TRAP, '^', /* 398 */ 0, 0, 99, 1, 0, 0, 0, 0, 0, {0,0} , 10}, /* Gold list (All types of gold and gems are defined here) */ {"copper" ,0x00000000L, TV_GOLD, '$', /* 399 */ 0, 3, 1, 1, 0, 0, 0, 0, 0, {0,0} , 1}, {"copper" ,0x00000000L, TV_GOLD, '$', 0, 4, 2, 1, 0, 0, 0, 0, 0, {0,0} , 1}, {"copper" ,0x00000000L, TV_GOLD, '$', 0, 5, 3, 1, 0, 0, 0, 0, 0, {0,0} , 1}, {"silver" ,0x00000000L, TV_GOLD, '$', 0, 6, 4, 1, 0, 0, 0, 0, 0, {0,0} , 1}, {"silver" ,0x00000000L, TV_GOLD, '$', 0, 7, 5, 1, 0, 0, 0, 0, 0, {0,0} , 1}, {"silver" ,0x00000000L, TV_GOLD, '$', 0, 8, 6, 1, 0, 0, 0, 0, 0, {0,0} , 1}, {"garnets" ,0x00000000L, TV_GOLD, '*', 0, 9, 7, 1, 0, 0, 0, 0, 0, {0,0} , 1}, {"garnets" ,0x00000000L, TV_GOLD, '*', 0, 10, 8, 1, 0, 0, 0, 0, 0, {0,0} , 1}, {"gold" ,0x00000000L, TV_GOLD, '$', 0, 12, 9, 1, 0, 0, 0, 0, 0, {0,0} , 1}, {"gold" ,0x00000000L, TV_GOLD, '$', 0, 14, 10, 1, 0, 0, 0, 0, 0, {0,0} , 1}, {"gold" ,0x00000000L, TV_GOLD, '$', 0, 16, 11, 1, 0, 0, 0, 0, 0, {0,0} , 1}, {"opals" ,0x00000000L, TV_GOLD, '*', 0, 18, 12, 1, 0, 0, 0, 0, 0, {0,0} , 1}, {"sapphires" ,0x00000000L, TV_GOLD, '*', 0, 20, 13, 1, 0, 0, 0, 0, 0, {0,0} , 1}, {"gold" ,0x00000000L, TV_GOLD, '$', 0, 24, 14, 1, 0, 0, 0, 0, 0, {0,0} , 1}, {"rubies" ,0x00000000L, TV_GOLD, '*', 0, 28, 15, 1, 0, 0, 0, 0, 0, {0,0} , 1}, {"diamonds" ,0x00000000L, TV_GOLD, '*', 0, 32, 16, 1, 0, 0, 0, 0, 0, {0,0} , 1}, {"emeralds" ,0x00000000L, TV_GOLD, '*', 0, 40, 17, 1, 0, 0, 0, 0, 0, {0,0} , 1}, {"mithril" ,0x00000000L, TV_GOLD, '$', /* 416 */ 0, 80, 18, 1, 0, 0, 0, 0, 0, {0,0} , 1}, /* nothing, used as inventory place holder */ /* must be stackable, so that can be picked up by inven_carry */ {"nothing" ,0x00000000L, TV_NOTHING, ' ', /* 417 */ 0, 0, 64, 0, 0, 0, 0, 0, 0, {0,0} , 0}, /* these next two are needed only for the names */ {"& ruined chest" ,0x00000000L, TV_CHEST, '&', /* 418 */ 0, 0, 0, 1, 250, 0, 0, 0, 0, {0,0} , 0}, {"" ,0x00000000L, TV_NOTHING, ' ', /* 419 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, {0,0} , 0} }; #endif char *special_names[SN_ARRAY_SIZE] = { CNIL, "(R)", "(RA)", "(RF)", "(RC)", "(RL)", "(HA)", "(DF)", "(SA)", "(SD)", "(SE)", "(SU)", "(FT)", "(FB)", "of Free Action", "of Slaying", "of Clumsiness", "of Weakness", "of Slow Descent", "of Speed", "of Stealth", "of Slowness", "of Noise", "of Great Mass", "of Intelligence", "of Wisdom", "of Infra-Vision", "of Might", "of Lordliness", "of the Magi", "of Beauty", "of Seeing", "of Regeneration", "of Stupidity", "of Dullness", "of Blindness", "of Timidness", "of Teleportation", "of Ugliness", "of Protection", "of Irritation", "of Vulnerability", "of Enveloping", "of Fire", "of Slay Evil", "of Dragon Slaying", "(Empty)", "(Locked)", "(Poison Needle)", "(Gas Trap)", "(Explosion Device)", "(Summoning Runes)", "(Multiple Traps)", "(Disarmed)", "(Unlocked)", "of Slay Animal" }; /* Pairing things down for THINK C. */ #ifndef RSRC_PART2 int16 sorted_objects[MAX_DUNGEON_OBJ]; /* Identified objects flags */ int8u object_ident[OBJECT_IDENT_SIZE]; int16 t_level[MAX_OBJ_LEVEL+1]; inven_type t_list[MAX_TALLOC]; inven_type inventory[INVEN_ARRAY_SIZE]; #endif /* Treasure related values */ int16 inven_ctr = 0; /* Total different obj's */ int16 inven_weight = 0; /* Cur carried weight */ int16 equip_ctr = 0; /* Cur equipment ctr */ int16 tcptr; /* Cur treasure heap ptr */ moria-5.6.debian.1/source/config.h0000644000175000017500000002706711074756544015132 0ustar pjbpjb/* source/config.h: configuration definitions Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #define CONFIG_H_INCLUDED #ifdef CONSTANT_H_INCLUDED Constant.h should always be included after config.h, because it uses some of the system defines set up here. #endif /* Person to bother if something goes wrong. */ /* Recompile files.c and misc2.c if this changes. */ #define WIZARD "David Grabiner " /* The wizard password and wizard uid are no longer used. */ /* System definitions. You must define one of these as appropriate for the system you are compiling moria on. */ /* No system definition is needed for 4.3BSD, SUN OS, DG/UX. */ /* Unless you're on a system, like an HP Apollo, that doesn't let more than one machine access a file at a time; then define this. */ /* #define APOLLO */ /* If compiling on Debian (also works on other versions of Linux), define this. */ #define DEBIAN_LINUX /* If you are compiling on an ultrix/4.2BSD/Dynix/etc. version of UNIX, define this. It is not needed for SUNs. */ /* #ifndef ultrix #define ultrix #endif */ /* If you are compiling under IBM's AIX 3.0, then you can either define SYS_V, or you can define nothing (thus compiling as if on a BSD system) but you must comment out the AIX LFLAG line in the Makefile so that moria will be linked with -lbsd. */ /* If you are compiling on a SYS V version of UNIX, define this. */ /* #define SYS_V */ /* If you are compiling on a SYS III version of UNIX, define this. The SYS_III support may not be complete. I do not know if this works. */ /* #define SYS_III */ /* If you are compiling on an ATARI ST with Mark Williams C, define this. */ /* #define ATARIST_MWC */ /* If you are compiling on an Atari ST with GCC, you do not need to define anything. */ /* If you are compiling on an Atari ST with TC, define this. */ /* #define ATARIST_TC */ /* If you are compiling on a Macintosh with MPW C 3.0, define this. */ /* #define MAC */ /* If we are in Think C, then we must be on a mac. */ #ifdef THINK_C #define MAC #endif /* For Xenix systems, define SYS_V and unix. */ #ifdef M_XENIX #define SYS_V #define unix #endif /* If on HP-UX, define the name as we use it. */ #ifdef __hpux #define HPUX #endif /* If you are compiling under VMS, define this. */ /* #define VMS */ /* If you are using the tcio.c file instead of io.c, then define this. The tcio.c file uses TURBO C builtin functions instead of curses library calls. It only works if you are using TURBO C. The default is to assume you are using it if you are using TURBO C on an IBM-PC. */ #if defined(MSDOS) && defined(__TURBOC__) #define USING_TCIO #endif /* Files used by moria, set these to valid pathnames for your system. */ #ifdef MSDOS /* Files which can be in a varying place */ #define MORIA_SAV moriasav #define MORIA_TOP moriatop #define MORIA_MOR "news" #define MORIA_GPL "COPYING" #define MORIA_TOP_NAME "scores" #define MORIA_SAV_NAME "MORIA.SAV" #define MORIA_CNF_NAME "MORIA.CNF" #define MORIA_HELP "roglcmds.hlp" #define MORIA_ORIG_HELP "origcmds.hlp" #define MORIA_WIZ_HELP "rwizcmds.hlp" #define MORIA_OWIZ_HELP "owizcmds.hlp" #define MORIA_WELCOME "welcome.hlp" #define MORIA_VER "version.hlp" #else #ifdef MAC /* These files are concatenated into the data fork of the app */ /* The names are retained to find the appropriate text */ #define MORIA_MOR "news" #define MORIA_GPL "COPYING" #define MORIA_HELP "roglcmds.hlp" #define MORIA_ORIG_HELP "origcmds.hlp" #define MORIA_WIZ_HELP "rwizcmds.hlp" #define MORIA_OWIZ_HELP "owizcmds.hlp" #define MORIA_WELCOME "welcome.hlp" #define MORIA_VER "version.hlp" /* Do not know what will happen with these yet */ #define MORIA_TOP "Moria High Scores" /* File types and creators for the Mac */ #define MORIA_FCREATOR 'MRIA' #define SAVE_FTYPE 'SAVE' #define INFO_FTYPE 'TEXT' #define SCORE_FTYPE 'SCOR' #define CONFIG_FTYPE 'CNFG' /* Options for building resources: THINK C doesn't have -D switch, so we need to define this stuff here. Uncomment RSRC when building DumpRes1 or DumpRes2; uncomment RSRC_PARTn as appropriate. When building application, comment all of them. I don't think any of this is necessary for MPW C -- BS. */ #ifdef THINK_C /* #define RSRC */ /* This copy is for creating resources. */ /* THINK C can only take 32K data, so we need to dump the resources in two parts. */ /* #define RSRC_PART1 */ /* #define RSRC_PART2 */ #endif #else #ifdef VMS #define MORIA_SAV "moria.sav" /* These 3 files need a dot at the end to prevent VMS from deciding that they are *.DAT files or anything else equally wierd. */ #define MORIA_HOU "moria:hours." #define MORIA_MOR "moria:news." #define MORIA_GPL "moria:COPYING." #define MORIA_TOP "moria:scores." #define MORIA_HELP "moria:roglcmds.hlp" #define MORIA_ORIG_HELP "moria:origcmds.hlp" #define MORIA_WIZ_HELP "moria:rwizcmds.hlp" #define MORIA_OWIZ_HELP "moria:owizcmds.hlp" #define MORIA_WELCOME "moria:welcome.hlp" #define MORIA_VER "moria:version.hlp" #else #ifdef AMIGA #define MORIA_SAV "moria.sav" #define MORIA_HOU "moria:hours" #define MORIA_MOR "moria:news" #define MORIA_GPL "moria:COPYING" #define MORIA_TOP "moria:scores" #define MORIA_HELP "moria:roglcmds.hlp" #define MORIA_ORIG_HELP "moria:origcmds.hlp" #define MORIA_WIZ_HELP "moria:rwizcmds.hlp" #define MORIA_OWIZ_HELP "moria:owizcmds.hlp" #define MORIA_WELCOME "moria:welcome.hlp" #define MORIA_VER "moria:version.hlp" #else #if defined(GEMDOS) /* Atari ST */ #define MORIA_SAV "moria.sav" #define MORIA_HOU "files\\hours" #define MORIA_MOR "files\\news" #define MORIA_GPL "files\\COPYING" #define MORIA_TOP "files\\scores" #define MORIA_HELP "files\\roglcmds.hlp" #define MORIA_ORIG_HELP "files\\origcmds.hlp" #define MORIA_WIZ_HELP "files\\rwizcmds.hlp" #define MORIA_OWIZ_HELP "files\\owizcmds.hlp" #define MORIA_WELCOME "files\\welcome.hlp" #define MORIA_VER "files\\version.hlp" #else #if defined(atarist) && defined(__GNUC__) /* atari-st compiled with gnu-c */ #define MORIA_SAV "moria.save" #define MORIA_HOU (char *)prefix_file("files/hours") #define MORIA_MOR (char *)prefix_file("files/news") #define MORIA_GPL (char *)prefix_file("files/COPYING") #define MORIA_TOP (char *)prefix_file("files/scores") #define MORIA_HELP (char *)prefix_file("files/roglcmds.hlp") #define MORIA_ORIG_HELP (char *)prefix_file("files/origcmds.hlp") #define MORIA_WIZ_HELP (char *)prefix_file("files/rwizcmds.hlp") #define MORIA_OWIZ_HELP (char *)prefix_file("files/owizcmds.hlp") #define MORIA_WELCOME (char *)prefix_file("files/welcome.hlp") #define MORIA_VER (char *)prefix_file("files/version.hlp") #else #if 0 /* Debian standards for file location */ /* This must be unix; change file names as appropriate. */ #define MORIA_SAV ".moria-save" #define MORIA_HOU "/etc/moria-hours" #define MORIA_MOR "/usr/lib/games/moria/news" #define MORIA_GPL "/usr/lib/games/moria/COPYING" #define MORIA_TOP "/var/games/moria/scores" #define MORIA_HELP "/usr/lib/games/moria/roglcmds.hlp" #define MORIA_ORIG_HELP "/usr/lib/games/moria/origcmds.hlp" #define MORIA_WIZ_HELP "/usr/lib/games/moria/rwizcmds.hlp" #define MORIA_OWIZ_HELP "/usr/lib/games/moria/owizcmds.hlp" #define MORIA_WELCOME "/usr/lib/games/moria/welcome.hlp" #define MORIA_VER "/usr/lib/games/moria/version.hlp" #else /* Generic UNIX */ /* This must be unix; change file names as appropriate. */ #define MORIA_SAV "moria-save" #define MORIA_HOU "/home/dgrabiner/moria-5.6/files/hours" #define MORIA_MOR "/home/dgrabiner/moria-5.6/files/news" #define MORIA_GPL "/home/dgrabiner/moria-5.6/files/COPYING" #define MORIA_TOP "/home/dgrabiner/moria-5.6/files/scores" #define MORIA_HELP "/home/dgrabiner/moria-5.6/files/roglcmds.hlp" #define MORIA_ORIG_HELP "/home/dgrabiner/moria-5.6/files/origcmds.hlp" #define MORIA_WIZ_HELP "/home/dgrabiner/moria-5.6/files/rwizcmds.hlp" #define MORIA_OWIZ_HELP "/home/dgrabiner/moria-5.6/files/owizcmds.hlp" #define MORIA_WELCOME "/home/dgrabiner/moria-5.6/files/welcome.hlp" #define MORIA_VER "/home/dgrabiner/moria-5.6/files/version.hlp" #endif #endif #endif #endif #endif #endif #endif /* This sets the default user interface. */ /* To use the original key bindings (keypad for movement) set ROGUE_LIKE to FALSE; to use the rogue-like key bindings (vi style movement) set ROGUE_LIKE to TRUE. */ /* If you change this, you only need to recompile main.c. */ #define ROGUE_LIKE FALSE /* For the ANDREW distributed file system, define this to ensure that the program is secure with respect to the setuid code, this prohibits inferior shells. It also does not relinquish setuid privileges at the start, but instead calls the ANDREW library routines bePlayer(), beGames(), and Authenticate(). */ /* #define SECURE */ /* System dependent defines follow. You should not need to change anything below. */ #ifdef ATARIST_TC #define USG /* #include Needed for TC ...printf but now universal */ #endif #if defined(ATARIST_TC) || defined(ATARIST_MWC) #define ATARI_ST #endif #if defined(__linux__) /* Linux supports System V */ #define SYS_V #endif /* Substitute strchr for index on USG versions of UNIX. */ #if defined(SYS_V) || defined(MSDOS) || defined(MAC) || defined(VMS) #define index strchr #endif #if defined(ATARIST_TC) || (defined(AMIGA) && defined(LATTICE)) #define index strchr #endif #ifdef SYS_III char *index(); #endif /* Define USG for many systems, this is basically to select SYS V style system calls (as opposed to BSD style). */ #if defined(SYS_III) || defined(SYS_V) || defined(MSDOS) || defined(MAC) #ifndef USG #define USG #endif #endif #if defined(ATARIST_MWC) || defined(AMIGA) || defined(VMS) #define USG #endif #ifdef AMIGA #ifndef ultrix #define ultrix #endif #endif /* Pyramid runs 4.2BSD-like UNIX version */ #if defined(Pyramid) #define ultrix #endif #if defined(_MSC_VER) && (_MSC_VER < 600) #define register /* MSC 4.0 still has a problem with register bugs ... */ #endif #ifdef MAC #ifdef RSRC #define MACRSRC /* Defined if we are building the resources. */ #else #define MACGAME /* Defined if we are building the game. */ #endif #endif #ifdef MAC /* Screen dimensions */ #define SCRN_ROWS 24 #define SCRN_COLS 80 #endif #ifdef VMS #define unlink delete #define index strchr #define exit uexit /* In constants.h, ESCAPE is defined to be the CTRL-Z key, instead of the escape key. */ #endif #if defined(SYS_V) && defined(lint) /* Define this to prevent from including on a PC/RT running AIX. This prevents a bunch of lint errors. */ #define RTPC_NO_NLS #endif #ifdef SECURE extern int PlayerUID; #define getuid() PlayerUID #define geteuid() PlayerUID #endif #ifdef THINK_C /* Apparently, THINK C is only happy if this is defined. This can not be defined in general, because some systems have include files which merely test whether STDC is defined, they do not test the value. */ /* Check how standard we are: Some code tests value of __STDC__. */ #ifndef __STDC__ #define __STDC__ 0 #endif #endif moria-5.6.debian.1/source/player.c0000644000175000017500000004713011074756544015145 0ustar pjbpjb/* source/player.c: player specific variable definitions Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include "config.h" #include "constant.h" #include "types.h" /* Player record for most player related info */ player_type py; /* player location in dungeon */ int16 char_row; int16 char_col; /* calculated base hp values for player at each level, store them so that drain life + restore life does not affect hit points */ int16u player_hp[MAX_PLAYER_LEVEL]; /* Class titles for different levels */ #ifdef MACGAME char *(*player_title)[MAX_PLAYER_LEVEL]; #else char *player_title[MAX_CLASS][MAX_PLAYER_LEVEL] = { /* Warrior */ {"Rookie","Private","Soldier","Mercenary","Veteran(1st)","Veteran(2nd)", "Veteran(3rd)","Warrior(1st)","Warrior(2nd)","Warrior(3rd)","Warrior(4th)", "Swordsman-1","Swordsman-2","Swordsman-3","Hero","Swashbuckler","Myrmidon", "Champion-1","Champion-2","Champion-3","Superhero","Knight","Superior Knt", "Gallant Knt","Knt Errant","Guardian Knt","Baron","Duke","Lord (1st)", "Lord (2nd)","Lord (3rd)","Lord (4th)","Lord (5th)","Lord (6th)","Lord (7th)", "Lord (8th)","Lord (9th)","Lord Gallant","Lord Keeper","Lord Noble"}, /* Mage */ {"Novice","Apprentice","Trickster-1","Trickster-2","Trickster-3","Cabalist-1", "Cabalist-2","Cabalist-3","Visionist","Phantasmist","Shadowist","Spellbinder", "Illusionist","Evoker (1st)","Evoker (2nd)","Evoker (3rd)","Evoker (4th)", "Conjurer","Theurgist","Thaumaturge","Magician","Enchanter","Warlock", "Sorcerer","Necromancer","Mage (1st)","Mage (2nd)","Mage (3rd)","Mage (4th)", "Mage (5th)","Wizard (1st)","Wizard (2nd)","Wizard (3rd)","Wizard (4th)", "Wizard (5th)","Wizard (6th)","Wizard (7th)","Wizard (8th)","Wizard (9th)", "Wizard Lord"}, /* Priests */ {"Believer","Acolyte(1st)","Acolyte(2nd)","Acolyte(3rd)","Adept (1st)", "Adept (2nd)","Adept (3rd)","Priest (1st)","Priest (2nd)","Priest (3rd)", "Priest (4th)","Priest (5th)","Priest (6th)","Priest (7th)","Priest (8th)", "Priest (9th)","Curate (1st)","Curate (2nd)","Curate (3rd)","Curate (4th)", "Curate (5th)","Curate (6th)","Curate (7th)","Curate (8th)","Curate (9th)", "Canon (1st)","Canon (2nd)","Canon (3rd)","Canon (4th)","Canon (5th)", "Low Lama","Lama-1","Lama-2","Lama-3","High Lama","Great Lama","Patriarch", "High Priest","Great Priest","Noble Priest"}, /* Rogues */ {"Vagabond","Footpad","Cutpurse","Robber","Burglar","Filcher","Sharper", "Magsman","Common Rogue","Rogue (1st)","Rogue (2nd)","Rogue (3rd)", "Rogue (4th)","Rogue (5th)","Rogue (6th)","Rogue (7th)","Rogue (8th)", "Rogue (9th)","Master Rogue","Expert Rogue","Senior Rogue","Chief Rogue", "Prime Rogue","Low Thief","Thief (1st)","Thief (2nd)","Thief (3rd)", "Thief (4th)","Thief (5th)","Thief (6th)","Thief (7th)","Thief (8th)", "Thief (9th)","High Thief","Master Thief","Executioner","Low Assassin", "Assassin","High Assassin","Guildsmaster"}, /* Rangers */ {"Runner (1st)","Runner (2nd)","Runner (3rd)","Strider (1st)","Strider (2nd)", "Strider (3rd)","Scout (1st)","Scout (2nd)","Scout (3rd)","Scout (4th)", "Scout (5th)","Courser (1st)","Courser (2nd)","Courser (3rd)","Courser (4th)", "Courser (5th)","Tracker (1st)","Tracker (2nd)","Tracker (3rd)", "Tracker (4th)","Tracker (5th)","Tracker (6th)","Tracker (7th)", "Tracker (8th)","Tracker (9th)","Guide (1st)","Guide (2nd)","Guide (3rd)", "Guide (4th)","Guide (5th)","Guide (6th)","Guide (7th)","Guide (8th)", "Guide (9th)","Pathfinder-1","Pathfinder-2","Pathfinder-3","Ranger", "High Ranger","Ranger Lord"}, /* Paladins */ {"Gallant","Keeper (1st)","Keeper (2nd)","Keeper (3rd)","Keeper (4th)", "Keeper (5th)","Keeper (6th)","Keeper (7th)","Keeper (8th)","Keeper (9th)", "Protector-1","Protector-2","Protector-3","Protector-4","Protector-5", "Protector-6","Protector-7","Protector-8","Defender-1","Defender-2", "Defender-3","Defender-4","Defender-5","Defender-6","Defender-7","Defender-8", "Warder (1st)","Warder (2nd)","Warder (3rd)","Warder (4th)","Warder (5th)", "Warder (6th)","Warder (7th)","Warder (8th)","Warder (9th)","Guardian", "Chevalier","Justiciar","Paladin","High Lord"} }; #endif /* Base experience levels, may be adjusted up for race and/or class*/ int32u player_exp[MAX_PLAYER_LEVEL] = { 10, 25, 45, 70, 100, 140, 200, 280, 380, 500, 650, 850, 1100, 1400, 1800, 2300, 2900, 3600, 4400, 5400, 6800, 8400, 10200, 12500, 17500, 25000, 35000L, 50000L, 75000L, 100000L, 150000L, 200000L, 300000L, 400000L, 500000L, 750000L, 1500000L, 2500000L, 5000000L, 10000000L }; /*Race STR,INT,WIS,DEX,CON,CHR, Ages, heights, and weights (male then female) Racial Bases for: dis,srh,stl,fos,bth,bthb,bsav,hitdie, infra, exp base, choice-classes */ #ifdef MACGAME race_type *race; #else race_type race[MAX_RACES] = { {"Human", 0, 0, 0, 0, 0, 0, 14, 6, 72, 6,180, 25, 66, 4,150, 20, 0, 0, 0, 0, 0, 0, 0, 10, 0, 100, 0x3F, }, {"Half-Elf", -1, 1, 0, 1, -1, 1, 24, 16, 66, 6,130, 15, 62, 6,100, 10, 2, 6, 1, -1, -1, 5, 3, 9, 2, 110, 0x3F, }, {"Elf", -1, 2, 1, 1, -2, 1, 75, 75, 60, 4,100, 6, 54, 4, 80, 6, 5, 8, 1, -2, -5, 15, 6, 8, 3, 120, 0x1F, }, {"Halfling", -2, 2, 1, 3, 1, 1, 21, 12, 36, 3, 60, 3, 33, 3, 50, 3, 15, 12, 4, -5,-10, 20, 18, 6, 4, 110, 0x0B, }, {"Gnome", -1, 2, 0, 2, 1, -2, 50, 40, 42, 3, 90, 6, 39, 3, 75, 3, 10, 6, 3, -3, -8, 12, 12, 7, 4, 125, 0x0F, }, {"Dwarf", 2, -3, 1, -2, 2, -3, 35, 15, 48, 3,150, 10, 46, 3,120, 10, 2, 7, -1, 0, 15, 0, 9, 9, 5, 120, 0x05, }, {"Half-Orc", 2, -1, 0, 0, 1, -4, 11, 4, 66, 1,150, 5, 62, 1,120, 5, -3, 0, -1, 3, 12, -5, -3, 10, 3, 110, 0x0D, }, {"Half-Troll",4, -4, -2, -4, 3, -6, 20, 10, 96, 10,255, 50, 84, 8,225, 40, -5, -1, -2, 5, 20,-10, -8, 12, 3, 120, 0x05, } }; #endif /* Background information */ #ifdef MACGAME background_type *background; #else background_type background[MAX_BACKGROUND] = { {"You are the illegitimate and unacknowledged child ", 10, 1, 2, 25}, {"You are the illegitimate but acknowledged child ", 20, 1, 2, 35}, {"You are one of several children ", 95, 1, 2, 45}, {"You are the first child ", 100, 1, 2, 50}, {"of a Serf. ", 40, 2, 3, 65}, {"of a Yeoman. ", 65, 2, 3, 80}, {"of a Townsman. ", 80, 2, 3, 90}, {"of a Guildsman. ", 90, 2, 3,105}, {"of a Landed Knight. ", 96, 2, 3,120}, {"of a Titled Noble. ", 99, 2, 3,130}, {"of a Royal Blood Line. ", 100, 2, 3,140}, {"You are the black sheep of the family. ", 20, 3,50, 20}, {"You are a credit to the family. ", 80, 3,50, 55}, {"You are a well liked child. ", 100, 3,50, 60}, {"Your mother was a Green-Elf. ", 40, 4, 1, 50}, {"Your father was a Green-Elf. ", 75, 4, 1, 55}, {"Your mother was a Grey-Elf. ", 90, 4, 1, 55}, {"Your father was a Grey-Elf. ", 95, 4, 1, 60}, {"Your mother was a High-Elf. ", 98, 4, 1, 65}, {"Your father was a High-Elf. ", 100, 4, 1, 70}, {"You are one of several children ", 60, 7, 8, 50}, {"You are the only child ", 100, 7, 8, 55}, {"of a Green-Elf ", 75, 8, 9, 50}, {"of a Grey-Elf ", 95, 8, 9, 55}, {"of a High-Elf ", 100, 8, 9, 60}, {"Ranger. ", 40, 9,54, 80}, {"Archer. ", 70, 9,54, 90}, {"Warrior. ", 87, 9,54,110}, {"Mage. ", 95, 9,54,125}, {"Prince. ", 99, 9,54,140}, {"King. ", 100, 9,54,145}, {"You are one of several children of a Halfling ", 85,10,11, 45}, {"You are the only child of a Halfling ", 100,10,11, 55}, {"Bum. ", 20,11, 3, 55}, {"Tavern Owner. ", 30,11, 3, 80}, {"Miller. ", 40,11, 3, 90}, {"Home Owner. ", 50,11, 3,100}, {"Burglar. ", 80,11, 3,110}, {"Warrior. ", 95,11, 3,115}, {"Mage. ", 99,11, 3,125}, {"Clan Elder. ", 100,11, 3,140}, {"You are one of several children of a Gnome ", 85,13,14, 45}, {"You are the only child of a Gnome ", 100,13,14, 55}, {"Beggar. ", 20,14, 3, 55}, {"Braggart. ", 50,14, 3, 70}, {"Prankster. ", 75,14, 3, 85}, {"Warrior. ", 95,14, 3,100}, {"Mage. ", 100,14, 3,125}, {"You are one of two children of a Dwarven ", 25,16,17, 40}, {"You are the only child of a Dwarven ", 100,16,17, 50}, {"Thief. ", 10,17,18, 60}, {"Prison Guard. ", 25,17,18, 75}, {"Miner. ", 75,17,18, 90}, {"Warrior. ", 90,17,18,110}, {"Priest. ", 99,17,18,130}, {"King. ", 100,17,18,150}, {"You are the black sheep of the family. ", 15,18,57, 10}, {"You are a credit to the family. ", 85,18,57, 50}, {"You are a well liked child. ", 100,18,57, 55}, {"Your mother was an Orc, but it is unacknowledged. ", 25,19,20, 25}, {"Your father was an Orc, but it is unacknowledged. ", 100,19,20, 25}, {"You are the adopted child ", 100,20, 2, 50}, {"Your mother was a Cave-Troll ", 30,22,23, 20}, {"Your father was a Cave-Troll ", 60,22,23, 25}, {"Your mother was a Hill-Troll ", 75,22,23, 30}, {"Your father was a Hill-Troll ", 90,22,23, 35}, {"Your mother was a Water-Troll ", 95,22,23, 40}, {"Your father was a Water-Troll ", 100,22,23, 45}, {"Cook. ", 5,23,62, 60}, {"Warrior. ", 95,23,62, 55}, {"Shaman. ", 99,23,62, 65}, {"Clan Chief. ", 100,23,62, 80}, {"You have dark brown eyes, ", 20,50,51, 50}, {"You have brown eyes, ", 60,50,51, 50}, {"You have hazel eyes, ", 70,50,51, 50}, {"You have green eyes, ", 80,50,51, 50}, {"You have blue eyes, ", 90,50,51, 50}, {"You have blue-gray eyes, ", 100,50,51, 50}, {"straight ", 70,51,52, 50}, {"wavy ", 90,51,52, 50}, {"curly ", 100,51,52, 50}, {"black hair, ", 30,52,53, 50}, {"brown hair, ", 70,52,53, 50}, {"auburn hair, ", 80,52,53, 50}, {"red hair, ", 90,52,53, 50}, {"blond hair, ", 100,52,53, 50}, {"and a very dark complexion.", 10,53, 0, 50}, {"and a dark complexion.", 30,53, 0, 50}, {"and an average complexion.", 80,53, 0, 50}, {"and a fair complexion.", 90,53, 0, 50}, {"and a very fair complexion.", 100,53, 0, 50}, {"You have light grey eyes, ", 85,54,55, 50}, {"You have light blue eyes, ", 95,54,55, 50}, {"You have light green eyes, ", 100,54,55, 50}, {"straight ", 75,55,56, 50}, {"wavy ", 100,55,56, 50}, {"black hair, and a fair complexion.", 75,56, 0, 50}, {"brown hair, and a fair complexion.", 85,56, 0, 50}, {"blond hair, and a fair complexion.", 95,56, 0, 50}, {"silver hair, and a fair complexion.", 100,56, 0, 50}, {"You have dark brown eyes, ", 99,57,58, 50}, {"You have glowing red eyes, ", 100,57,58, 60}, {"straight ", 90,58,59, 50}, {"wavy ", 100,58,59, 50}, {"black hair, ", 75,59,60, 50}, {"brown hair, ", 100,59,60, 50}, {"a one foot beard, ", 25,60,61, 50}, {"a two foot beard, ", 60,60,61, 51}, {"a three foot beard, ", 90,60,61, 53}, {"a four foot beard, ", 100,60,61, 55}, {"and a dark complexion.", 100,61, 0, 50}, {"You have slime green eyes, ", 60,62,63, 50}, {"You have puke yellow eyes, ", 85,62,63, 50}, {"You have blue-bloodshot eyes, ", 99,62,63, 50}, {"You have glowing red eyes, ", 100,62,63, 55}, {"dirty ", 33,63,64, 50}, {"mangy ", 66,63,64, 50}, {"oily ", 100,63,64, 50}, {"sea-weed green hair, ", 33,64,65, 50}, {"bright red hair, ", 66,64,65, 50}, {"dark purple hair, ", 100,64,65, 50}, {"and green ", 25,65,66, 50}, {"and blue ", 50,65,66, 50}, {"and white ", 75,65,66, 50}, {"and black ", 100,65,66, 50}, {"ulcerous skin.", 33,66, 0, 50}, {"scabby skin.", 66,66, 0, 50}, {"leprous skin.", 100,66, 0, 50} }; #endif /* Classes. */ class_type class[MAX_CLASS] = { /* HP Dis Src Stl Fos bth btb sve S I W D Co Ch Spell Exp spl */ {"Warrior",9, 25, 14, 1, 38, 70, 55, 18, 5,-2,-2, 2, 2,-1, NONE, 0, 0}, {"Mage", 0, 30, 16, 2, 20, 34, 20, 36,-5, 3, 0, 1,-2, 1, MAGE, 30, 1}, {"Priest", 2, 25, 16, 2, 32, 48, 35, 30,-3,-3, 3,-1, 0, 2, PRIEST, 20, 1}, {"Rogue", 6, 45, 32, 5, 16, 60, 66, 30, 2, 1,-2, 3, 1,-1, MAGE, 0, 5}, {"Ranger", 4, 30, 24, 3, 24, 56, 72, 30, 2, 2, 0, 1, 1, 1, MAGE, 40, 3}, {"Paladin",6, 20, 12, 1, 38, 68, 40, 24, 3,-3, 1, 0, 2, 2, PRIEST, 35, 1} }; /* making it 16 bits wastes a little space, but saves much signed/unsigned headaches in its use */ /* CLA_MISC_HIT is identical to CLA_SAVE, which takes advantage of the fact that the save values are independent of the class */ int16 class_level_adj[MAX_CLASS][MAX_LEV_ADJ] = { /* bth bthb device disarm save/misc hit */ /* Warrior */ { 4, 4, 2, 2, 3 }, /* Mage */ { 2, 2, 4, 3, 3 }, /* Priest */ { 2, 2, 4, 3, 3 }, /* Rogue */ { 3, 4, 3, 4, 3 }, /* Ranger */ { 3, 4, 3, 3, 3 }, /* Paladin */ { 3, 3, 3, 2, 3 } }; int32u spell_learned = 0; /* bit mask of spells learned */ int32u spell_worked = 0; /* bit mask of spells tried and worked */ int32u spell_forgotten = 0; /* bit mask of spells learned but forgotten */ int8u spell_order[32]; /* order spells learned/remembered/forgotten */ /* Warriors don't have spells, so there is no entry for them. Note that this means you must always subtract one from the py.misc.pclass before indexing into magic_spell[]. */ #ifdef MACGAME spell_type (*magic_spell)[31]; #else spell_type magic_spell[MAX_CLASS-1][31] = { { /* Mage */ { 1, 1, 22, 1}, { 1, 1, 23, 1}, { 1, 2, 24, 1}, { 1, 2, 26, 1}, { 3, 3, 25, 2}, { 3, 3, 25, 1}, { 3, 3, 27, 2}, { 3, 4, 30, 1}, { 5, 4, 30, 6}, { 5, 5, 30, 8}, { 5, 5, 30, 5}, { 5, 5, 35, 6}, { 7, 6, 35, 9}, { 7, 6, 50, 10}, { 7, 6, 40, 12}, { 9, 7, 44, 19}, { 9, 7, 45, 19}, { 9, 7, 75, 22}, { 9, 7, 45, 19}, { 11, 7, 45, 25}, { 11, 7, 99, 19}, { 13, 7, 50, 22}, { 15, 9, 50, 25}, { 17, 9, 50, 31}, { 19, 12, 55, 38}, { 21, 12, 90, 44}, { 23, 12, 60, 50}, { 25, 12, 65, 63}, { 29, 18, 65, 88}, { 33, 21, 80, 125}, { 37, 25, 95, 200} }, { /* Priest */ { 1, 1, 10, 1}, { 1, 2, 15, 1}, { 1, 2, 20, 1}, { 1, 2, 25, 1}, { 3, 2, 25, 1}, { 3, 3, 27, 2}, { 3, 3, 27, 2}, { 3, 3, 28, 3}, { 5, 4, 29, 4}, { 5, 4, 30, 5}, { 5, 4, 32, 5}, { 5, 5, 34, 5}, { 7, 5, 36, 6}, { 7, 5, 38, 7}, { 7, 6, 38, 9}, { 7, 7, 38, 9}, { 9, 6, 38, 10}, { 9, 7, 38, 10}, { 9, 7, 40, 10}, { 11, 8, 42, 10}, { 11, 8, 42, 12}, { 11, 9, 55, 15}, { 13, 10, 45, 15}, { 13, 11, 45, 16}, { 15, 12, 50, 20}, { 15, 14, 50, 22}, { 17, 14, 55, 32}, { 21, 16, 60, 38}, { 25, 20, 70, 75}, { 33, 24, 90, 125}, { 39, 32, 80, 200} }, { /* Rogue */ { 99, 99, 0, 0}, { 5, 1, 50, 1}, { 7, 2, 55, 1}, { 9, 3, 60, 2}, { 11, 4, 65, 2}, { 13, 5, 70, 3}, { 99, 99, 0, 0}, { 15, 6, 75, 3}, { 99, 99, 0, 0}, { 17, 7, 80, 4}, { 19, 8, 85, 5}, { 21, 9, 90, 6}, { 99, 99, 0, 0}, { 23, 10, 95, 7}, { 99, 99, 0, 0}, { 99, 99, 0, 0}, { 25, 12, 95, 9}, { 27, 15, 99, 11}, { 99, 99, 0, 0}, { 99, 99, 0, 0}, { 29, 18, 99, 19}, { 99, 99, 0, 0}, { 99, 99, 0, 0}, { 99, 99, 0, 0}, { 99, 99, 0, 0}, { 99, 99, 0, 0}, { 99, 99, 0, 0}, { 99, 99, 0, 0}, { 99, 99, 0, 0}, { 99, 99, 0, 0}, { 99, 99, 0, 0}, }, { /* Ranger */ { 3, 1, 30, 1}, { 3, 2, 35, 2}, { 3, 2, 35, 2}, { 5, 3, 35, 2}, { 5, 3, 40, 2}, { 5, 4, 45, 3}, { 7, 5, 40, 6}, { 7, 6, 40, 5}, { 9, 7, 40, 7}, { 9, 8, 45, 8}, { 11, 8, 40, 10}, { 11, 9, 45, 10}, { 13, 10, 45, 12}, { 13, 11, 55, 13}, { 15, 12, 50, 15}, { 15, 13, 50, 15}, { 17, 17, 55, 15}, { 17, 17, 90, 17}, { 21, 17, 55, 17}, { 21, 19, 60, 18}, { 23, 25, 95, 20}, { 23, 20, 60, 20}, { 25, 20, 60, 20}, { 25, 21, 65, 20}, { 27, 21, 65, 22}, { 29, 23, 95, 23}, { 31, 25, 70, 25}, { 33, 25, 75, 38}, { 35, 25, 80, 50}, { 37, 30, 95, 100}, { 99, 99, 0, 0} }, { /* Paladin */ { 1, 1, 30, 1}, { 2, 2, 35, 2}, { 3, 3, 35, 3}, { 5, 3, 35, 5}, { 5, 4, 35, 5}, { 7, 5, 40, 6}, { 7, 5, 40, 6}, { 9, 7, 40, 7}, { 9, 7, 40, 8}, { 9, 8, 40, 8}, { 11, 9, 40, 10}, { 11, 10, 45, 10}, { 11, 10, 45, 10}, { 13, 10, 45, 12}, { 13, 11, 45, 13}, { 15, 13, 45, 15}, { 15, 15, 50, 15}, { 17, 15, 50, 17}, { 17, 15, 50, 18}, { 19, 15, 50, 19}, { 19, 15, 50, 19}, { 21, 17, 50, 20}, { 23, 17, 50, 20}, { 25, 20, 50, 20}, { 27, 21, 50, 22}, { 29, 22, 50, 24}, { 31, 24, 60, 25}, { 33, 28, 60, 31}, { 35, 32, 70, 38}, { 37, 36, 90, 50}, { 39, 38, 90, 100} } }; #endif char *spell_names[62] = { /* Mage Spells */ "Magic Missile", "Detect Monsters", "Phase Door", "Light Area", "Cure Light Wounds", "Find Hidden Traps/Doors", "Stinking Cloud", "Confusion", "Lightning Bolt", "Trap/Door Destruction", "Sleep I", "Cure Poison", "Teleport Self", "Remove Curse", "Frost Bolt", "Turn Stone to Mud", "Create Food", "Recharge Item I", "Sleep II", "Polymorph Other", "Identify", "Sleep III", "Fire Bolt", "Slow Monster", "Frost Ball", "Recharge Item II", "Teleport Other", "Haste Self", "Fire Ball", "Word of Destruction", "Genocide", /* Priest Spells, start at index 31 */ "Detect Evil", "Cure Light Wounds", "Bless", "Remove Fear", "Call Light", "Find Traps", "Detect Doors/Stairs", "Slow Poison", "Blind Creature", "Portal", "Cure Medium Wounds", "Chant", "Sanctuary", "Create Food", "Remove Curse", "Resist Heat and Cold", "Neutralize Poison", "Orb of Draining", "Cure Serious Wounds", "Sense Invisible", "Protection from Evil", "Earthquake", "Sense Surroundings", "Cure Critical Wounds", "Turn Undead", "Prayer", "Dispel Undead", "Heal", "Dispel Evil", "Glyph of Warding", "Holy Word" }; /* Each type of character starts out with a few provisions. */ /* Note that the entries refer to elements of the object_list[] array*/ /* 344 = Food Ration, 365 = Wooden Torch, 123 = Cloak, 318 = Beginners-Majik, 103 = Soft Leather Armor, 30 = Stiletto, 322 = Beginners Handbook */ int16u player_init[MAX_CLASS][5] = { { 344, 365, 123, 30, 103}, /* Warrior */ { 344, 365, 123, 30, 318}, /* Mage */ { 344, 365, 123, 30, 322}, /* Priest */ { 344, 365, 123, 30, 318}, /* Rogue */ { 344, 365, 123, 30, 318}, /* Ranger */ { 344, 365, 123, 30, 322} /* Paladin */ }; moria-5.6.debian.1/source/create.c0000644000175000017500000003174311074756544015117 0ustar pjbpjb/* source/create.c: create a player character Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #ifdef USG #ifndef ATARIST_MWC #include #endif #else #include #endif #if defined(LINT_ARGS) static void get_stats(void); static void change_stat(int, int16); static void get_all_stats(void); static void choose_race(void); static void print_history(void); static void get_history(void); static void get_sex(void); static void get_ahw(void); static void get_class(void); static int monval(int8u); static void get_money(void); #endif /* Generates character's stats -JWT- */ static void get_stats() { register int i, tot; int dice[18]; do { tot = 0; for (i = 0; i < 18; i++) { dice[i] = randint (3 + i % 3); /* Roll 3,4,5 sided dice once each */ tot += dice[i]; } } while (tot <= 42 || tot >= 54); for (i = 0; i < 6; i++) py.stats.max_stat[i] = 5 + dice[3*i] + dice[3*i+1] + dice[3*i+2]; } /* Changes stats by given amount -JWT- */ static void change_stat(stat, amount) int stat; int16 amount; { register int i; register int tmp_stat; tmp_stat = py.stats.max_stat[stat]; if (amount < 0) for (i = 0; i > amount; i--) { if (tmp_stat > 108) tmp_stat--; else if (tmp_stat > 88) tmp_stat += -randint(6) - 2; else if (tmp_stat > 18) { tmp_stat += -randint(15) - 5; if (tmp_stat < 18) tmp_stat = 18; } else if (tmp_stat > 3) tmp_stat--; } else for (i = 0; i < amount; i++) { if (tmp_stat < 18) tmp_stat++; else if (tmp_stat < 88) tmp_stat += randint(15) + 5; else if (tmp_stat < 108) tmp_stat += randint(6) + 2; else if (tmp_stat < 118) tmp_stat++; } py.stats.max_stat[stat] = tmp_stat; } /* generate all stats and modify for race. needed in a separate module so looping of character selection would be allowed -RGM- */ static void get_all_stats () { register player_type *p_ptr; register race_type *r_ptr; register int j; p_ptr = &py; r_ptr = &race[p_ptr->misc.prace]; get_stats (); change_stat (A_STR, r_ptr->str_adj); change_stat (A_INT, r_ptr->int_adj); change_stat (A_WIS, r_ptr->wis_adj); change_stat (A_DEX, r_ptr->dex_adj); change_stat (A_CON, r_ptr->con_adj); change_stat (A_CHR, r_ptr->chr_adj); p_ptr->misc.lev = 1; for (j = 0; j < 6; j++) { py.stats.cur_stat[j] = py.stats.max_stat[j]; set_use_stat (j); } p_ptr->misc.srh = r_ptr->srh; p_ptr->misc.bth = r_ptr->bth; p_ptr->misc.bthb = r_ptr->bthb; p_ptr->misc.fos = r_ptr->fos; p_ptr->misc.stl = r_ptr->stl; p_ptr->misc.save = r_ptr->bsav; p_ptr->misc.hitdie = r_ptr->bhitdie; p_ptr->misc.ptodam = todam_adj(); p_ptr->misc.ptohit = tohit_adj(); p_ptr->misc.ptoac = 0; p_ptr->misc.pac = toac_adj(); p_ptr->misc.expfact = r_ptr->b_exp; p_ptr->flags.see_infra = r_ptr->infra; } /* Allows player to select a race -JWT- */ static void choose_race() { register int j, k; int l, m, exit_flag; char s; char tmp_str[80]; register player_type *p_ptr; register race_type *r_ptr; j = 0; k = 0; l = 2; m = 21; clear_from (20); put_buffer("Choose a race (? for Help):", 20, 2); do { (void) sprintf(tmp_str, "%c) %s", k+'a', race[j].trace); put_buffer(tmp_str, m, l); k++; l += 15; if (l > 70) { l = 2; m++; } j++; } while (j < MAX_RACES); exit_flag = FALSE; do { move_cursor (20, 30); s = inkey(); j = s - 'a'; if ((j < MAX_RACES) && (j >= 0)) exit_flag = TRUE; else if (s == '?') helpfile (MORIA_WELCOME); else bell (); } while (!exit_flag); p_ptr = &py; r_ptr = &race[j]; p_ptr->misc.prace = j; put_buffer(r_ptr->trace, 3, 15); } /* Will print the history of a character -JWT- */ static void print_history() { register int i; put_buffer("Character Background", 14, 27); for (i = 0; i < 4; i++) prt(py.misc.history[i], i+15, 10); } /* Get the racial history, determines social class -RAK- */ /* Assumptions: Each race has init history beginning at */ /* (race-1)*3+1 */ /* All history parts are in ascending order */ static void get_history() { int hist_ptr, cur_ptr, test_roll, flag; register int start_pos, end_pos, cur_len; int line_ctr, new_start, social_class; char history_block[240]; register background_type *b_ptr; /* Get a block of history text */ hist_ptr = py.misc.prace*3 + 1; history_block[0] = '\0'; social_class = randint(4); cur_ptr = 0; do { flag = FALSE; do { if (background[cur_ptr].chart == hist_ptr) { test_roll = randint(100); while (test_roll > background[cur_ptr].roll) cur_ptr++; b_ptr = &background[cur_ptr]; (void) strcat(history_block, b_ptr->info); social_class += b_ptr->bonus - 50; if (hist_ptr > b_ptr->next) cur_ptr = 0; hist_ptr = b_ptr->next; flag = TRUE; } else cur_ptr++; } while (!flag); } while (hist_ptr >= 1); /* clear the previous history strings */ for (hist_ptr = 0; hist_ptr < 4; hist_ptr++) py.misc.history[hist_ptr][0] = '\0'; /* Process block of history text for pretty output */ start_pos = 0; end_pos = strlen(history_block) - 1; line_ctr = 0; flag = FALSE; while (history_block[end_pos] == ' ') end_pos--; do { while (history_block[start_pos] == ' ') start_pos++; cur_len = end_pos - start_pos + 1; if (cur_len > 60) { cur_len = 60; while (history_block[start_pos+cur_len-1] != ' ') cur_len--; new_start = start_pos + cur_len; while (history_block[start_pos+cur_len-1] == ' ') cur_len--; } else flag = TRUE; (void) strncpy(py.misc.history[line_ctr], &history_block[start_pos], cur_len); py.misc.history[line_ctr][cur_len] = '\0'; line_ctr++; start_pos = new_start; } while (!flag); /* Compute social class for player */ if (social_class > 100) social_class = 100; else if (social_class < 1) social_class = 1; py.misc.sc = social_class; } /* Gets the character's sex -JWT- */ static void get_sex() { register int exit_flag; char c; exit_flag = FALSE; clear_from (20); put_buffer("Choose a sex (? for Help):", 20, 2); put_buffer("m) Male f) Female", 21, 2); do { move_cursor (20, 29); /* speed not important here */ c = inkey(); if (c == 'f' || c == 'F') { py.misc.male = FALSE; put_buffer("Female", 4, 15); exit_flag = TRUE; } else if (c == 'm' || c == 'M') { py.misc.male = TRUE; put_buffer("Male", 4, 15); exit_flag = TRUE; } else if (c == '?') helpfile (MORIA_WELCOME); else bell (); } while (!exit_flag); } /* Computes character's age, height, and weight -JWT- */ static void get_ahw() { register int i; i = py.misc.prace; py.misc.age = race[i].b_age + randint((int)race[i].m_age); if (py.misc.male) { py.misc.ht = randnor((int)race[i].m_b_ht, (int)race[i].m_m_ht); py.misc.wt = randnor((int)race[i].m_b_wt, (int)race[i].m_m_wt); } else { py.misc.ht = randnor((int)race[i].f_b_ht, (int)race[i].f_m_ht); py.misc.wt = randnor((int)race[i].f_b_wt, (int)race[i].f_m_wt); } py.misc.disarm = race[i].b_dis + todis_adj(); } /* Gets a character class -JWT- */ static void get_class() { register int i, j; int k, l, m, min_value, max_value; int cl[MAX_CLASS], exit_flag; register struct misc *m_ptr; register player_type *p_ptr; class_type *c_ptr; char tmp_str[80], s; int32u mask; for (j = 0; j < MAX_CLASS; j++) cl[j] = 0; i = py.misc.prace; j = 0; k = 0; l = 2; m = 21; mask = 0x1; clear_from (20); put_buffer("Choose a class (? for Help):", 20, 2); do { if (race[i].rtclass & mask) { (void) sprintf(tmp_str, "%c) %s", k+'a', class[j].title); put_buffer(tmp_str, m, l); cl[k] = j; l += 15; if (l > 70) { l = 2; m++; } k++; } j++; mask <<= 1; } while (j < MAX_CLASS); py.misc.pclass = 0; exit_flag = FALSE; do { move_cursor (20, 31); s = inkey(); j = s - 'a'; if ((j < k) && (j >= 0)) { py.misc.pclass = cl[j]; c_ptr = &class[py.misc.pclass]; exit_flag = TRUE; clear_from (20); put_buffer(c_ptr->title, 5, 15); /* Adjust the stats for the class adjustment -RAK- */ p_ptr = &py; change_stat (A_STR, c_ptr->madj_str); change_stat (A_INT, c_ptr->madj_int); change_stat (A_WIS, c_ptr->madj_wis); change_stat (A_DEX, c_ptr->madj_dex); change_stat (A_CON, c_ptr->madj_con); change_stat (A_CHR, c_ptr->madj_chr); for(i = 0; i < 6; i++) { p_ptr->stats.cur_stat[i] = p_ptr->stats.max_stat[i]; set_use_stat(i); } p_ptr->misc.ptodam = todam_adj(); /* Real values */ p_ptr->misc.ptohit = tohit_adj(); p_ptr->misc.ptoac = toac_adj(); p_ptr->misc.pac = 0; p_ptr->misc.dis_td = p_ptr->misc.ptodam; /* Displayed values */ p_ptr->misc.dis_th = p_ptr->misc.ptohit; p_ptr->misc.dis_tac= p_ptr->misc.ptoac; p_ptr->misc.dis_ac = p_ptr->misc.pac + p_ptr->misc.dis_tac; /* now set misc stats, do this after setting stats because of con_adj() for hitpoints */ m_ptr = &py.misc; m_ptr->hitdie += c_ptr->adj_hd; m_ptr->mhp = con_adj() + m_ptr->hitdie; m_ptr->chp = m_ptr->mhp; m_ptr->chp_frac = 0; /* initialize hit_points array */ /* put bounds on total possible hp, only succeed if it is within 1/8 of average value */ min_value = (MAX_PLAYER_LEVEL*3/8 * (m_ptr->hitdie-1)) + MAX_PLAYER_LEVEL; max_value = (MAX_PLAYER_LEVEL*5/8 * (m_ptr->hitdie-1)) + MAX_PLAYER_LEVEL; player_hp[0] = m_ptr->hitdie; do { for (i = 1; i < MAX_PLAYER_LEVEL; i++) { #ifdef AMIGA /* Stupid Aztec C 5.0 bug work around CBG */ player_hp[i] = player_hp[i-1] + randint ((int)m_ptr->hitdie); #else player_hp[i] = randint((int)m_ptr->hitdie); player_hp[i] += player_hp[i-1]; #endif } } while ((player_hp[MAX_PLAYER_LEVEL-1] < min_value) || (player_hp[MAX_PLAYER_LEVEL-1] > max_value)); m_ptr->bth += c_ptr->mbth; m_ptr->bthb += c_ptr->mbthb; /*RAK*/ m_ptr->srh += c_ptr->msrh; m_ptr->disarm += c_ptr->mdis; m_ptr->fos += c_ptr->mfos; m_ptr->stl += c_ptr->mstl; m_ptr->save += c_ptr->msav; m_ptr->expfact += c_ptr->m_exp; } else if (s == '?') helpfile (MORIA_WELCOME); else bell (); } while (!exit_flag); } /* Given a stat value, return a monetary value, which affects the amount of gold a player has. */ static int monval (i) int8u i; { return 5 * ((int)i - 10); } static void get_money() { register int tmp, gold; register int8u *a_ptr; a_ptr = py.stats.max_stat; tmp = monval (a_ptr[A_STR]) + monval (a_ptr[A_INT]) + monval (a_ptr[A_WIS]) + monval (a_ptr[A_CON]) + monval (a_ptr[A_DEX]); gold = py.misc.sc*6 + randint (25) + 325; /* Social Class adj */ gold -= tmp; /* Stat adj */ gold += monval (a_ptr[A_CHR]); /* Charisma adj */ if (!py.misc.male) gold += 50; /* She charmed the banker into it! -CJS- */ if (gold < 80) gold = 80; /* Minimum */ py.misc.au = gold; } /* ---------- M A I N for Character Creation Routine ---------- */ /* -JWT- */ void create_character() { register int exit_flag = 1; register char c; put_character(); choose_race(); get_sex(); /* here we start a loop giving a player a choice of characters -RGM- */ get_all_stats (); get_history(); get_ahw(); print_history(); put_misc1(); put_stats(); clear_from (20); put_buffer("Hit space to reroll or ESC to accept characteristics: ", 20, 2); do { move_cursor (20, 56); c = inkey(); if (c == ESCAPE) exit_flag = 0; else if (c == ' ') { get_all_stats (); get_history(); get_ahw(); print_history(); put_misc1(); put_stats(); } else bell (); } /* done with stats generation */ while (exit_flag == 1); get_class(); get_money(); put_stats(); put_misc2(); put_misc3(); get_name(); /* This delay may be reduced, but is recommended to keep players */ /* from continuously rolling up characters, which can be VERY */ /* expensive CPU wise. */ pause_exit(23, PLAYER_EXIT_PAUSE); } moria-5.6.debian.1/source/wizard.c0000644000175000017500000002271711074756544015155 0ustar pjbpjb/* source/wizard.c: Version history and info, and wizard mode debugging aids. Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include #include #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #ifdef USG #ifndef ATARIST_MWC #include #endif #else #include #endif #ifdef ATARIST_TC /* Include this to get prototypes for standard library functions. */ #include #endif long atol(); /* Light up the dungeon -RAK- */ void wizard_light() { register cave_type *c_ptr; register int k, l, i, j; int flag; if (cave[char_row][char_col].pl) flag = FALSE; else flag = TRUE; for (i = 0; i < cur_height; i++) for (j = 0; j < cur_width; j++) if (cave[i][j].fval <= MAX_CAVE_FLOOR) for (k = i-1; k <= i+1; k++) for (l = j-1; l <= j+1; l++) { c_ptr = &cave[k][l]; c_ptr->pl = flag; if (!flag) c_ptr->fm = FALSE; } prt_map(); } /* Wizard routine for gaining on stats -RAK- */ void change_character() { register int tmp_val; register int32 tmp_lval; int8u *a_ptr; vtype tmp_str; register struct misc *m_ptr; a_ptr = py.stats.max_stat; prt("(3 - 118) Strength = ", 0, 0); if (get_string(tmp_str, 0, 25, 3)) { tmp_val = atoi(tmp_str); if ((tmp_val > 2) && (tmp_val < 119)) { a_ptr[A_STR] = tmp_val; (void) res_stat(A_STR); } } else return; prt("(3 - 118) Intelligence = ", 0, 0); if (get_string(tmp_str, 0, 25, 3)) { tmp_val = atoi(tmp_str); if ((tmp_val > 2) && (tmp_val < 119)) { a_ptr[A_INT] = tmp_val; (void) res_stat(A_INT); } } else return; prt("(3 - 118) Wisdom = ", 0, 0); if (get_string(tmp_str, 0, 25, 3)) { tmp_val = atoi(tmp_str); if ((tmp_val > 2) && (tmp_val < 119)) { a_ptr[A_WIS] = tmp_val; (void) res_stat(A_WIS); } } else return; prt("(3 - 118) Dexterity = ", 0, 0); if (get_string(tmp_str, 0, 25, 3)) { tmp_val = atoi(tmp_str); if ((tmp_val > 2) && (tmp_val < 119)) { a_ptr[A_DEX] = tmp_val; (void) res_stat(A_DEX); } } else return; prt("(3 - 118) Constitution = ", 0, 0); if (get_string(tmp_str, 0, 25, 3)) { tmp_val = atoi(tmp_str); if ((tmp_val > 2) && (tmp_val < 119)) { a_ptr[A_CON] = tmp_val; (void) res_stat(A_CON); } } else return; prt("(3 - 118) Charisma = ", 0, 0); if (get_string(tmp_str, 0, 25, 3)) { tmp_val = atoi(tmp_str); if ((tmp_val > 2) && (tmp_val < 119)) { a_ptr[A_CHR] = tmp_val; (void) res_stat(A_CHR); } } else return; m_ptr = &py.misc; prt("(1 - 32767) Hit points = ", 0, 0); if (get_string(tmp_str, 0, 25, 5)) { tmp_val = atoi(tmp_str); if ((tmp_val > 0) && (tmp_val <= MAX_SHORT)) { m_ptr->mhp = tmp_val; m_ptr->chp = tmp_val; m_ptr->chp_frac = 0; prt_mhp(); prt_chp(); } } else return; prt("(0 - 32767) Mana = ", 0, 0); if (get_string(tmp_str, 0, 25, 5)) { tmp_val = atoi(tmp_str); if ((tmp_val > -1) && (tmp_val <= MAX_SHORT) && (*tmp_str != '\0')) { m_ptr->mana = tmp_val; m_ptr->cmana = tmp_val; m_ptr->cmana_frac = 0; prt_cmana(); } } else return; (void) sprintf(tmp_str, "Current=%ld Gold = ", m_ptr->au); tmp_val = strlen(tmp_str); prt(tmp_str, 0, 0); if (get_string(tmp_str, 0, tmp_val, 7)) { tmp_lval = atol(tmp_str); if (tmp_lval > -1 && (*tmp_str != '\0')) { m_ptr->au = tmp_lval; prt_gold(); } } else return; (void) sprintf(tmp_str, "Current=%d (0-200) Searching = ", m_ptr->srh); tmp_val = strlen(tmp_str); prt(tmp_str, 0, 0); if (get_string(tmp_str, 0, tmp_val, 3)) { tmp_val = atoi(tmp_str); if ((tmp_val > -1) && (tmp_val < 201) && (*tmp_str != '\0')) m_ptr->srh = tmp_val; } else return; (void) sprintf(tmp_str, "Current=%d (-1-18) Stealth = ", m_ptr->stl); tmp_val = strlen(tmp_str); prt(tmp_str, 0, 0); if (get_string(tmp_str, 0, tmp_val, 3)) { tmp_val = atoi(tmp_str); if ((tmp_val > -2) && (tmp_val < 19) && (*tmp_str != '\0')) m_ptr->stl = tmp_val; } else return; (void) sprintf(tmp_str, "Current=%d (0-200) Disarming = ", m_ptr->disarm); tmp_val = strlen(tmp_str); prt(tmp_str, 0, 0); if (get_string(tmp_str, 0, tmp_val, 3)) { tmp_val = atoi(tmp_str); if ((tmp_val > -1) && (tmp_val < 201) && (*tmp_str != '\0')) m_ptr->disarm = tmp_val; } else return; (void) sprintf(tmp_str, "Current=%d (0-100) Save = ", m_ptr->save); tmp_val = strlen(tmp_str); prt(tmp_str, 0, 0); if (get_string(tmp_str, 0, tmp_val, 3)) { tmp_val = atoi(tmp_str); if ((tmp_val > -1) && (tmp_val < 201) && (*tmp_str != '\0')) m_ptr->save = tmp_val; } else return; (void) sprintf(tmp_str, "Current=%d (0-200) Base to hit = ", m_ptr->bth); tmp_val = strlen(tmp_str); prt(tmp_str, 0, 0); if (get_string(tmp_str, 0, tmp_val, 3)) { tmp_val = atoi(tmp_str); if ((tmp_val > -1) && (tmp_val < 201) && (*tmp_str != '\0')) m_ptr->bth = tmp_val; } else return; (void) sprintf(tmp_str, "Current=%d (0-200) Bows/Throwing = ", m_ptr->bthb); tmp_val = strlen(tmp_str); prt(tmp_str, 0, 0); if (get_string(tmp_str, 0, tmp_val, 3)) { tmp_val = atoi(tmp_str); if ((tmp_val > -1) && (tmp_val < 201) && (*tmp_str != '\0')) m_ptr->bthb = tmp_val; } else return; (void) sprintf(tmp_str, "Current=%d Weight = ", m_ptr->wt); tmp_val = strlen(tmp_str); prt(tmp_str, 0, 0); if (get_string(tmp_str, 0, tmp_val, 3)) { tmp_val = atoi(tmp_str); if (tmp_val > -1 && (*tmp_str != '\0')) m_ptr->wt = tmp_val; } else return; while(get_com("Alter speed? (+/-)", tmp_str)) { if (*tmp_str == '+') change_speed(-1); else if (*tmp_str == '-') change_speed(1); else break; prt_speed(); } } /* Wizard routine for creating objects -RAK- */ void wizard_create() { register int tmp_val; int32 tmp_lval; vtype tmp_str; register inven_type *i_ptr; inven_type forge; register cave_type *c_ptr; char pattern[4]; msg_print("Warning: This routine can cause a fatal error."); i_ptr = &forge; i_ptr->index = OBJ_WIZARD; i_ptr->name2 = 0; inscribe(i_ptr, "wizard item"); i_ptr->ident = ID_KNOWN2|ID_STOREBOUGHT; prt("Tval : ", 0, 0); if (!get_string(tmp_str, 0, 9, 3)) return; tmp_val = atoi(tmp_str); i_ptr->tval = tmp_val; prt("Tchar : ", 0, 0); if (!get_string(tmp_str, 0, 9, 1)) return; i_ptr->tchar = tmp_str[0]; prt("Subval : ", 0, 0); if (!get_string(tmp_str, 0, 9, 5)) return; tmp_val = atoi(tmp_str); i_ptr->subval = tmp_val; prt("Weight : ", 0, 0); if (!get_string(tmp_str, 0, 9, 5)) return; tmp_val = atoi(tmp_str); i_ptr->weight = tmp_val; prt("Number : ", 0, 0); if (!get_string(tmp_str, 0, 9, 5)) return; tmp_val = atoi(tmp_str); i_ptr->number = tmp_val; prt("Damage (dice): ", 0, 0); if (!get_string(tmp_str, 0, 15, 3)) return; tmp_val = atoi(tmp_str); i_ptr->damage[0] = tmp_val; prt("Damage (sides): ", 0, 0); if (!get_string(tmp_str, 0, 16, 3)) return; tmp_val = atoi(tmp_str); i_ptr->damage[1] = tmp_val; prt("+To hit: ", 0, 0); if (!get_string(tmp_str, 0, 9, 3)) return; tmp_val = atoi(tmp_str); i_ptr->tohit = tmp_val; prt("+To dam: ", 0, 0); if (!get_string(tmp_str, 0, 9, 3)) return; tmp_val = atoi(tmp_str); i_ptr->todam = tmp_val; prt("AC : ", 0, 0); if (!get_string(tmp_str, 0, 9, 3)) return; tmp_val = atoi(tmp_str); i_ptr->ac = tmp_val; prt("+To AC : ", 0, 0); if (!get_string(tmp_str, 0, 9, 3)) return; tmp_val = atoi(tmp_str); i_ptr->toac = tmp_val; prt("P1 : ", 0, 0); if (!get_string(tmp_str, 0, 9, 5)) return; tmp_val = atoi(tmp_str); i_ptr->p1 = tmp_val; prt("Flags (In HEX): ", 0, 0); if (!get_string(tmp_str, 0, 16, 8)) return; /* can't be constant string, this causes problems with the GCC compiler and some scanf routines */ (void) strcpy (pattern, "%lx"); (void) sscanf(tmp_str, pattern, &tmp_lval); i_ptr->flags = tmp_lval; prt("Cost : ", 0, 0); if (!get_string(tmp_str, 0, 9, 8)) return; tmp_lval = atol(tmp_str); i_ptr->cost = tmp_lval; prt("Level : ", 0, 0); if (!get_string(tmp_str, 0, 10, 3)) return; tmp_val = atoi(tmp_str); i_ptr->level = tmp_val; if (get_check("Allocate?")) { /* delete object first if any, before call popt */ c_ptr = &cave[char_row][char_col]; if (c_ptr->tptr != 0) (void) delete_object(char_row, char_col); tmp_val = popt(); t_list[tmp_val] = forge; c_ptr->tptr = tmp_val; msg_print("Allocated."); } else msg_print("Aborted."); } moria-5.6.debian.1/source/store1.c0000644000175000017500000003023111074756544015060 0ustar pjbpjb/* source/store1.c: store code, updating store inventory, pricing objects Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #ifdef USG #ifndef ATARIST_MWC #include #endif #else #include #endif #if defined(LINT_ARGS) static void insert_store(int, int, int32, struct inven_type *); static void store_create(int); #else static void insert_store(); static void store_create(); #endif /* Returns the value for any given object -RAK- */ int32 item_value(i_ptr) register inven_type *i_ptr; { register int32 value; value = i_ptr->cost; /* don't purchase known cursed items */ if (i_ptr->ident & ID_DAMD) value = 0; else if (((i_ptr->tval >= TV_BOW) && (i_ptr->tval <= TV_SWORD)) || ((i_ptr->tval >= TV_BOOTS) && (i_ptr->tval <= TV_SOFT_ARMOR))) { /* Weapons and armor */ if (!known2_p(i_ptr)) value = object_list[i_ptr->index].cost; else if ((i_ptr->tval >= TV_BOW) && (i_ptr->tval <= TV_SWORD)) { if (i_ptr->tohit < 0) value = 0; else if (i_ptr->todam < 0) value = 0; else if (i_ptr->toac < 0) value = 0; else value = i_ptr->cost+(i_ptr->tohit+i_ptr->todam+i_ptr->toac)*100; } else { if (i_ptr->toac < 0) value = 0; else value = i_ptr->cost+i_ptr->toac*100; } } else if ((i_ptr->tval >= TV_SLING_AMMO) && (i_ptr->tval <= TV_SPIKE)) { /* Ammo */ if (!known2_p(i_ptr)) value = object_list[i_ptr->index].cost; else { if (i_ptr->tohit < 0) value = 0; else if (i_ptr->todam < 0) value = 0; else if (i_ptr->toac < 0) value = 0; else /* use 5, because missiles generally appear in groups of 20, so 20 * 5 == 100, which is comparable to weapon bonus above */ value = i_ptr->cost+(i_ptr->tohit+i_ptr->todam+i_ptr->toac)*5; } } else if ((i_ptr->tval == TV_SCROLL1) || (i_ptr->tval == TV_SCROLL2) || (i_ptr->tval == TV_POTION1) || (i_ptr->tval == TV_POTION2)) { /* Potions, Scrolls, and Food */ if (!known1_p(i_ptr)) value = 20; } else if (i_ptr->tval == TV_FOOD) { if ((i_ptr->subval < (ITEM_SINGLE_STACK_MIN + MAX_MUSH)) && !known1_p(i_ptr)) value = 1; } else if ((i_ptr->tval == TV_AMULET) || (i_ptr->tval == TV_RING)) { /* Rings and amulets */ if (!known1_p(i_ptr)) /* player does not know what type of ring/amulet this is */ value = 45; else if (!known2_p(i_ptr)) /* player knows what type of ring, but does not know whether it is cursed or not, if refuse to buy cursed objects here, then player can use this to 'identify' cursed objects */ value = object_list[i_ptr->index].cost; } else if ((i_ptr->tval == TV_STAFF) || (i_ptr->tval == TV_WAND)) { /* Wands and staffs*/ if (!known1_p(i_ptr)) { if (i_ptr->tval == TV_WAND) value = 50; else value = 70; } else if (known2_p(i_ptr)) value = i_ptr->cost + (i_ptr->cost / 20) * i_ptr->p1; } /* picks and shovels */ else if (i_ptr->tval == TV_DIGGING) { if (!known2_p(i_ptr)) value = object_list[i_ptr->index].cost; else { if (i_ptr->p1 < 0) value = 0; else { /* some digging tools start with non-zero p1 values, so only multiply the plusses by 100, make sure result is positive */ value = i_ptr->cost + (i_ptr->p1 - object_list[i_ptr->index].p1) * 100; if (value < 0) value = 0; } } } /* multiply value by number of items if it is a group stack item */ if (i_ptr->subval > ITEM_GROUP_MIN) /* do not include torches here */ value = value * i_ptr->number; return(value); } /* Asking price for an item -RAK- */ int32 sell_price(snum, max_sell, min_sell, item) int snum; int32 *max_sell, *min_sell; inven_type *item; { register int32 i; register store_type *s_ptr; s_ptr = &store[snum]; i = item_value(item); /* check item->cost in case it is cursed, check i in case it is damaged */ if ((item->cost > 0) && (i > 0)) { i = i * rgold_adj[owners[s_ptr->owner].owner_race][py.misc.prace] / 100; if (i < 1) i = 1; *max_sell = i * owners[s_ptr->owner].max_inflate / 100; *min_sell = i * owners[s_ptr->owner].min_inflate / 100; if (*min_sell > *max_sell) *min_sell = *max_sell; return(i); } else /* don't let the item get into the store inventory */ return(0); } /* Check to see if he will be carrying too many objects -RAK- */ int store_check_num(t_ptr, store_num) inven_type *t_ptr; int store_num; { register int store_check, i; register store_type *s_ptr; register inven_type *i_ptr; store_check = FALSE; s_ptr = &store[store_num]; if (s_ptr->store_ctr < STORE_INVEN_MAX) store_check = TRUE; else if (t_ptr->subval >= ITEM_SINGLE_STACK_MIN) for (i = 0; i < s_ptr->store_ctr; i++) { i_ptr = &s_ptr->store_inven[i].sitem; /* note: items with subval of gte ITEM_SINGLE_STACK_MAX only stack if their subvals match */ if (i_ptr->tval == t_ptr->tval && i_ptr->subval == t_ptr->subval && ((int)i_ptr->number + (int)t_ptr->number < 256) && (t_ptr->subval < ITEM_GROUP_MIN || (i_ptr->p1 == t_ptr->p1))) store_check = TRUE; } return(store_check); } /* Insert INVEN_MAX at given location */ static void insert_store(store_num, pos, icost, i_ptr) register int pos; int store_num; int32 icost; inven_type *i_ptr; { register int i; register store_type *s_ptr; s_ptr = &store[store_num]; for (i = s_ptr->store_ctr-1; i >= pos; i--) s_ptr->store_inven[i+1] = s_ptr->store_inven[i]; s_ptr->store_inven[pos].sitem = *i_ptr; s_ptr->store_inven[pos].scost = -icost; s_ptr->store_ctr++; } /* Add the item in INVEN_MAX to stores inventory. -RAK- */ void store_carry(store_num, ipos, t_ptr) int store_num; int *ipos; inven_type *t_ptr; { int item_num, item_val, flag; register int typ, subt; int32 icost, dummy; register inven_type *i_ptr; register store_type *s_ptr; *ipos = -1; if (sell_price(store_num, &icost, &dummy, t_ptr) > 0) { s_ptr = &store[store_num]; item_val = 0; item_num = t_ptr->number; flag = FALSE; typ = t_ptr->tval; subt = t_ptr->subval; do { i_ptr = &s_ptr->store_inven[item_val].sitem; if (typ == i_ptr->tval) { if (subt == i_ptr->subval && /* Adds to other item */ subt >= ITEM_SINGLE_STACK_MIN && (subt < ITEM_GROUP_MIN || i_ptr->p1 == t_ptr->p1)) { *ipos = item_val; i_ptr->number += item_num; /* must set new scost for group items, do this only for items strictly greater than group_min, not for torches, this must be recalculated for entire group */ if (subt > ITEM_GROUP_MIN) { (void) sell_price (store_num, &icost, &dummy, i_ptr); s_ptr->store_inven[item_val].scost = -icost; } /* must let group objects (except torches) stack over 24 since there may be more than 24 in the group */ else if (i_ptr->number > 24) i_ptr->number = 24; flag = TRUE; } } else if (typ > i_ptr->tval) { /* Insert into list */ insert_store(store_num, item_val, icost, t_ptr); flag = TRUE; *ipos = item_val; } item_val++; } while ((item_val < s_ptr->store_ctr) && (!flag)); if (!flag) /* Becomes last item in list */ { insert_store(store_num, (int)s_ptr->store_ctr, icost, t_ptr); *ipos = s_ptr->store_ctr - 1; } } } /* Destroy an item in the stores inventory. Note that if */ /* "one_of" is false, an entire slot is destroyed -RAK- */ void store_destroy(store_num, item_val, one_of) int store_num, item_val; int one_of; { register int j, number; register store_type *s_ptr; register inven_type *i_ptr; s_ptr = &store[store_num]; i_ptr = &s_ptr->store_inven[item_val].sitem; /* for single stackable objects, only destroy one half on average, this will help ensure that general store and alchemist have reasonable selection of objects */ if ((i_ptr->subval >= ITEM_SINGLE_STACK_MIN) && (i_ptr->subval <= ITEM_SINGLE_STACK_MAX)) { if (one_of) number = 1; else number = randint((int)i_ptr->number); } else number = i_ptr->number; if (number != i_ptr->number) i_ptr->number -= number; else { for (j = item_val; j < s_ptr->store_ctr-1; j++) s_ptr->store_inven[j] = s_ptr->store_inven[j+1]; invcopy(&s_ptr->store_inven[s_ptr->store_ctr-1].sitem, OBJ_NOTHING); s_ptr->store_inven[s_ptr->store_ctr-1].scost = 0; s_ptr->store_ctr--; } } /* Initializes the stores with owners -RAK- */ void store_init() { register int i, j, k; register store_type *s_ptr; i = MAX_OWNERS / MAX_STORES; for (j = 0; j < MAX_STORES; j++) { s_ptr = &store[j]; s_ptr->owner = MAX_STORES*(randint(i)-1) + j; s_ptr->insult_cur = 0; s_ptr->store_open = 0; s_ptr->store_ctr = 0; s_ptr->good_buy = 0; s_ptr->bad_buy = 0; for (k = 0; k < STORE_INVEN_MAX; k++) { invcopy(&s_ptr->store_inven[k].sitem, OBJ_NOTHING); s_ptr->store_inven[k].scost = 0; } } } /* Creates an item and inserts it into store's inven -RAK- */ static void store_create(store_num) int store_num; { register int i, tries; int cur_pos, dummy; register store_type *s_ptr; register inven_type *t_ptr; tries = 0; cur_pos = popt(); s_ptr = &store[store_num]; do { i = store_choice[store_num][randint(STORE_CHOICES)-1]; invcopy(&t_list[cur_pos], i); magic_treasure(cur_pos, OBJ_TOWN_LEVEL); t_ptr = &t_list[cur_pos]; if (store_check_num(t_ptr, store_num)) { if ((t_ptr->cost > 0) && /* Item must be good */ (t_ptr->cost < owners[s_ptr->owner].max_cost)) { /* equivalent to calling ident_spell(), except will not change the object_ident array */ store_bought(t_ptr); store_carry(store_num, &dummy, t_ptr); tries = 10; } } tries++; } while (tries <= 3); pusht((int8u)cur_pos); } /* Initialize and up-keep the store's inventory. -RAK- */ void store_maint() { register int i, j; register store_type *s_ptr; for (i = 0; i < MAX_STORES; i++) { s_ptr = &store[i]; s_ptr->insult_cur = 0; if (s_ptr->store_ctr >= STORE_MIN_INVEN) { j = randint(STORE_TURN_AROUND); if (s_ptr->store_ctr >= STORE_MAX_INVEN) j += 1 + s_ptr->store_ctr - STORE_MAX_INVEN; while (--j >= 0) store_destroy(i, randint((int)s_ptr->store_ctr)-1, FALSE); } if (s_ptr->store_ctr <= STORE_MAX_INVEN) { j = randint(STORE_TURN_AROUND); if (s_ptr->store_ctr < STORE_MIN_INVEN) j += STORE_MIN_INVEN - s_ptr->store_ctr; while (--j >= 0) store_create(i); } } } /* eliminate need to bargain if player has haggled well in the past -DJB- */ int noneedtobargain(store_num, minprice) int store_num; int32 minprice; { register int flagnoneed; int bargain_record; register store_type *s_ptr; s_ptr = &store[store_num]; if (s_ptr->good_buy == MAX_SHORT) return TRUE; bargain_record = (s_ptr->good_buy - 3 * s_ptr->bad_buy - 5); flagnoneed = ((bargain_record > 0) && ((long)bargain_record * (long)bargain_record > minprice/50)); return (flagnoneed); } /* update the bargin info -DJB- */ void updatebargain(store_num, price, minprice) int store_num; int32 price, minprice; { register store_type *s_ptr; s_ptr = &store[store_num]; if (minprice > 9) if (price == minprice) { if (s_ptr->good_buy < MAX_SHORT) s_ptr->good_buy++; } else { if (s_ptr->bad_buy < MAX_SHORT) s_ptr->bad_buy++; } } moria-5.6.debian.1/source/recall.c0000644000175000017500000004341711074756544015117 0ustar pjbpjb/* source/recall.c: print out monster memory info -CJS- Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #if defined(LINT_ARGS) static void roff(char *); #else static void roff(); #endif static char *desc_atype[] = { "do something undefined", "attack", "weaken", "confuse", "terrify", "shoot flames", "shoot acid", "freeze", "shoot lightning", "corrode", "blind", "paralyse", "steal money", "steal things", "poison", "reduce dexterity", "reduce constitution", "drain intelligence", "drain wisdom", "lower experience", "call for help", "disenchant", "eat your food", "absorb light", "absorb charges" }; static char *desc_amethod[] = { "make an undefined advance", "hit", "bite", "claw", "sting", "touch", "kick", "gaze", "breathe", "spit", "wail", "embrace", "crawl on you", "release spores", "beg", "slime you", "crush", "trample", "drool", "insult" }; static char *desc_howmuch[] = { " not at all", " a bit", "", " quite", " very", " most", " highly", " extremely" }; static char *desc_move[] = { "move invisibly", "open doors", "pass through walls", "kill weaker creatures", "pick up objects", "breed explosively" }; static char *desc_spell[] = { "teleport short distances", "teleport long distances", "teleport its prey", "cause light wounds", "cause serious wounds", "paralyse its prey", "induce blindness", "confuse", "terrify", "summon a monster", "summon the undead", "slow its prey", "drain mana", "unknown 1", "unknown 2" }; static char *desc_breath[] = { "lightning", "poison gases", "acid", "frost", "fire" }; static char *desc_weakness[] = { "frost", "fire", "poison", "acid", "bright light", "rock remover" }; static vtype roffbuf; /* Line buffer. */ static char *roffp; /* Pointer into line buffer. */ static int roffpline; /* Place to print line now being loaded. */ #define plural(c, ss, sp) ((c) == 1 ? ss : sp) /* Number of kills needed for information. */ /* the higher the level of the monster, the fewer the kills you need */ #define knowarmor(l,d) ((d) > 304 / (4 + (l))) /* the higher the level of the monster, the fewer the attacks you need, the more damage an attack does, the more attacks you need */ #define knowdamage(l,a,d) ((4 + (l))*(a) > 80 * (d)) /* Do we know anything about this monster? */ int bool_roff_recall(mon_num) int mon_num; { register recall_type *mp; register int i; if (wizard) return TRUE; mp = &c_recall[mon_num]; if (mp->r_cmove || mp->r_cdefense || mp->r_kills || mp->r_spells || mp->r_deaths) return TRUE; for (i = 0; i < 4; i++) if (mp->r_attacks[i]) return TRUE; return FALSE; } /* Print out what we have discovered about this monster. */ int roff_recall(mon_num) int mon_num; { char *p, *q; int8u *pu; vtype temp; register recall_type *mp; register creature_type *cp; register int i, k; register int32u j; int32 templong; int mspeed; int32u rcmove, rspells; int16u rcdefense; recall_type save_mem; #ifdef ATARIST_MWC int32u holder; int32u holder2; #endif mp = &c_recall[mon_num]; cp = &c_list[mon_num]; if (wizard) { save_mem = *mp; mp->r_kills = MAX_SHORT; mp->r_wake = mp->r_ignore = MAX_UCHAR; #ifdef ATARIST_MWC j = (((cp->cmove & (holder = CM_4D2_OBJ)) != 0) * 8) + (((cp->cmove & (holder = CM_2D2_OBJ)) != 0) * 4) + (((cp->cmove & (holder = CM_1D2_OBJ)) != 0) * 2) + ((cp->cmove & (holder = CM_90_RANDOM)) != 0) + ((cp->cmove & (holder = CM_60_RANDOM)) != 0); holder = CM_TREASURE; mp->r_cmove = (cp->cmove & ~holder) | (j << CM_TR_SHIFT); #else j = (((cp->cmove & CM_4D2_OBJ) != 0) * 8) + (((cp->cmove & CM_2D2_OBJ) != 0) * 4) + (((cp->cmove & CM_1D2_OBJ) != 0) * 2) + ((cp->cmove & CM_90_RANDOM) != 0) + ((cp->cmove & CM_60_RANDOM) != 0); mp->r_cmove = (cp->cmove & ~CM_TREASURE) | (j << CM_TR_SHIFT); #endif mp->r_cdefense = cp->cdefense; #ifdef ATARIST_MWC if (cp->spells & (holder = CS_FREQ)) #else if (cp->spells & CS_FREQ) #endif mp->r_spells = cp->spells | CS_FREQ; else mp->r_spells = cp->spells; j = 0; pu = cp->damage; while (*pu != 0 && j < 4) { /* Turbo C needs a 16 bit int for the array index. */ mp->r_attacks[(int)j] = MAX_UCHAR; j++; pu++; } /* A little hack to enable the display of info for Quylthulgs. */ if (mp->r_cmove & CM_ONLY_MAGIC) mp->r_attacks[0] = MAX_UCHAR; } roffpline = 0; roffp = roffbuf; #ifdef ATARIST_MWC holder = ~CS_FREQ; rspells = mp->r_spells & cp->spells & holder; /* the CM_WIN property is always known, set it if a win monster */ holder = CM_WIN; rcmove = mp->r_cmove | (holder & cp->cmove); #else rspells = mp->r_spells & cp->spells & ~CS_FREQ; /* the CM_WIN property is always known, set it if a win monster */ rcmove = mp->r_cmove | (CM_WIN & cp->cmove); #endif rcdefense = mp->r_cdefense & cp->cdefense; (void) sprintf(temp, "The %s:\n", cp->name); roff(temp); /* Conflict history. */ if(mp->r_deaths) { (void) sprintf(temp, "%d of the contributors to your monster memory %s", mp->r_deaths, plural(mp->r_deaths, "has", "have") ); roff(temp); roff(" been killed by this creature, and "); if (mp->r_kills == 0) roff("it is not ever known to have been defeated."); else { (void) sprintf(temp, "at least %d of the beasts %s been exterminated.", mp->r_kills, plural(mp->r_kills, "has", "have") ); roff(temp); } } else if (mp->r_kills) { (void) sprintf(temp, "At least %d of these creatures %s", mp->r_kills, plural(mp->r_kills, "has", "have") ); roff(temp); roff(" been killed by contributors to your monster memory."); } else roff("No known battles to the death are recalled."); /* Immediately obvious. */ k = FALSE; if (cp->level == 0) { roff(" It lives in the town"); k = TRUE; } else if (mp->r_kills) { /* The Balrog is a level 100 monster, but appears at 50 feet. */ i = cp->level; if (i > WIN_MON_APPEAR) i = WIN_MON_APPEAR; (void) sprintf(temp, " It is normally found at depths of %d feet", i * 50); roff(temp); k = TRUE; } /* the c_list speed value is 10 greater, so that it can be a int8u */ mspeed = cp->speed - 10; if (rcmove & CM_ALL_MV_FLAGS) { if (k) roff(", and"); else { roff(" It"); k = TRUE; } roff(" moves"); if (rcmove & CM_RANDOM_MOVE) { /* Turbo C needs a 16 bit int for the array index. */ roff(desc_howmuch[(int)((rcmove & CM_RANDOM_MOVE) >> 3)]); roff(" erratically"); } if (mspeed == 1) roff(" at normal speed"); else { if (rcmove & CM_RANDOM_MOVE) roff(", and"); if (mspeed <= 0) { if (mspeed == -1) roff(" very"); else if (mspeed < -1) roff(" incredibly"); roff(" slowly"); } else { if (mspeed == 3) roff(" very"); else if (mspeed > 3) roff(" unbelievably"); roff(" quickly"); } } } if (rcmove & CM_ATTACK_ONLY) { if(k) roff(", but"); else { roff(" It"); k = TRUE; } roff(" does not deign to chase intruders"); } if (rcmove & CM_ONLY_MAGIC) { if (k) roff (", but"); else { roff (" It"); k = TRUE; } roff (" always moves and attacks by using magic"); } if(k) roff("."); /* Kill it once to know experience, and quality (evil, undead, monsterous). The quality of being a dragon is obvious. */ if (mp->r_kills) { roff(" A kill of this"); if (cp->cdefense & CD_ANIMAL) roff(" natural"); if (cp->cdefense & CD_EVIL) roff(" evil"); if (cp->cdefense & CD_UNDEAD) roff(" undead"); /* calculate the integer exp part, can be larger than 64K when first level character looks at Balrog info, so must store in long */ templong = (long)cp->mexp * cp->level / py.misc.lev; /* calculate the fractional exp part scaled by 100, must use long arithmetic to avoid overflow */ j = (((long)cp->mexp * cp->level % py.misc.lev) * (long)1000 / py.misc.lev+5) / 10; (void) sprintf(temp, " creature is worth %ld.%02ld point%s", templong, j, (templong == 1 && j == 0 ? "" : "s")); roff(temp); if (py.misc.lev / 10 == 1) p = "th"; else { i = py.misc.lev % 10; if (i == 1) p = "st"; else if (i == 2) p = "nd"; else if (i == 3) p = "rd"; else p = "th"; } i = py.misc.lev; if (i == 8 || i == 11 || i == 18) q = "n"; else q = ""; (void) sprintf(temp, " for a%s %d%s level character.", q, i, p); roff(temp); } /* Spells known, if have been used against us. Breath weapons or resistance might be known only because we cast spells at it. */ k = TRUE; j = rspells; #ifdef ATARIST_MWC holder = CS_BREATHE; holder2 = CS_BR_LIGHT; for (i = 0; j & holder; i++) #else for (i = 0; j & CS_BREATHE; i++) #endif { #ifdef ATARIST_MWC if (j & (holder2 << i)) #else if (j & (CS_BR_LIGHT << i)) #endif { #ifdef ATARIST_MWC j &= ~(holder2 << i); #else j &= ~(CS_BR_LIGHT << i); #endif if (k) { #ifdef ATARIST_MWC holder2 = CS_FREQ; if (mp->r_spells & holder2) #else if (mp->r_spells & CS_FREQ) #endif roff(" It can breathe "); else roff(" It is resistant to "); k = FALSE; } #ifdef ATARIST_MWC else if (j & holder) #else else if (j & CS_BREATHE) #endif roff(", "); else roff(" and "); roff(desc_breath[i]); } } k = TRUE; #ifdef ATARIST_MWC holder = CS_SPELLS; for (i = 0; j & holder; i++) #else for (i = 0; j & CS_SPELLS; i++) #endif { if (j & (CS_TEL_SHORT << i)) { j &= ~(CS_TEL_SHORT << i); if (k) { #ifdef ATARIST_MWC holder2 = CS_BREATHE; if (rspells & holder2) #else if (rspells & CS_BREATHE) #endif roff(", and is also"); else roff(" It is"); roff(" magical, casting spells which "); k = FALSE; } #ifdef ATARIST_MWC else if (j & holder) #else else if (j & CS_SPELLS) #endif roff(", "); else roff(" or "); roff(desc_spell[i]); } } #ifdef ATARIST_MWC holder = CS_BREATHE|CS_SPELLS; if (rspells & holder) #else if (rspells & (CS_BREATHE|CS_SPELLS)) #endif { if ((mp->r_spells & CS_FREQ) > 5) { /* Could offset by level */ (void) sprintf(temp, "; 1 time in %ld", cp->spells & CS_FREQ); roff(temp); } roff("."); } /* Do we know how hard they are to kill? Armor class, hit die. */ if (knowarmor(cp->level, mp->r_kills)) { (void) sprintf(temp, " It has an armor rating of %d", cp->ac); roff(temp); (void) sprintf(temp, " and a%s life rating of %dd%d.", ((cp->cdefense & CD_MAX_HP) ? " maximized" : ""), cp->hd[0], cp->hd[1]); roff(temp); } /* Do we know how clever they are? Special abilities. */ k = TRUE; j = rcmove; #ifdef ATARIST_MWC holder = CM_SPECIAL; holder2 = CM_INVISIBLE; for (i = 0; j & holder; i++) #else for (i = 0; j & CM_SPECIAL; i++) #endif { #ifdef ATARIST_MWC if (j & (holder2 << i)) #else if (j & (CM_INVISIBLE << i)) #endif { #ifdef ATARIST_MWC j &= ~(holder2 << i); #else j &= ~(CM_INVISIBLE << i); #endif if (k) { roff(" It can "); k = FALSE; } #ifdef ATARIST_MWC else if (j & holder) #else else if (j & CM_SPECIAL) #endif roff(", "); else roff(" and "); roff(desc_move[i]); } } if (!k) roff("."); /* Do we know its special weaknesses? Most cdefense flags. */ k = TRUE; j = rcdefense; for (i = 0; j & CD_WEAKNESS; i++) { if (j & (CD_FROST << i)) { j &= ~(CD_FROST << i); if (k) { roff(" It is susceptible to "); k = FALSE; } else if (j & CD_WEAKNESS) roff(", "); else roff(" and "); roff(desc_weakness[i]); } } if (!k) roff("."); if (rcdefense & CD_INFRA) roff(" It is warm blooded"); if (rcdefense & CD_NO_SLEEP) { if (rcdefense & CD_INFRA) roff(", and"); else roff(" It"); roff(" cannot be charmed or slept"); } if (rcdefense & (CD_NO_SLEEP|CD_INFRA)) roff("."); /* Do we know how aware it is? */ if (((mp->r_wake * mp->r_wake) > cp->sleep) || mp->r_ignore == MAX_UCHAR || (cp->sleep == 0 && mp->r_kills >= 10)) { roff(" It "); if(cp->sleep > 200) roff("prefers to ignore"); else if(cp->sleep > 95) roff("pays very little attention to"); else if(cp->sleep > 75) roff("pays little attention to"); else if(cp->sleep > 45) roff("tends to overlook"); else if(cp->sleep > 25) roff("takes quite a while to see"); else if(cp->sleep > 10) roff("takes a while to see"); else if(cp->sleep > 5) roff("is fairly observant of"); else if(cp->sleep > 3) roff("is observant of"); else if(cp->sleep > 1) roff("is very observant of"); else if(cp->sleep != 0) roff("is vigilant for"); else roff("is ever vigilant for"); (void) sprintf(temp, " intruders, which it may notice from %d feet.", 10 * cp->aaf); roff(temp); } /* Do we know what it might carry? */ #ifdef ATARIST_MWC holder = CM_CARRY_OBJ|CM_CARRY_BOLD; if (rcmove & holder) #else if (rcmove & (CM_CARRY_OBJ|CM_CARRY_GOLD)) #endif { roff(" It may"); #ifdef ATARIST_MWC j = (rcmove & (holder = CM_TREASURE)) >> CM_TR_SHIFT; #else j = (rcmove & CM_TREASURE) >> CM_TR_SHIFT; #endif if (j == 1) { #ifdef ATARIST_MWC if ((cp->cmove & (holder = CM_TREASURE)) == CM_60_RANDOM) #else if ((cp->cmove & CM_TREASURE) == CM_60_RANDOM) #endif roff(" sometimes"); else roff(" often"); } #ifdef ATARIST_MWC else if ((j == 2) && ((cp->cmove & (holder = CM_TREASURE)) == #else else if ((j == 2) && ((cp->cmove & CM_TREASURE) == #endif (CM_60_RANDOM|CM_90_RANDOM))) roff (" often"); roff(" carry"); #ifdef ATARIST_MWC holder = CM_SMALL_OBJ; if (rcmove & holder) #else if (rcmove & CM_SMALL_OBJ) #endif p = " small objects"; else p = " objects"; if (j == 1) { #ifdef ATARIST_MWC if (rcmove & holder) #else if (rcmove & CM_SMALL_OBJ) #endif p = " a small object"; else p = " an object"; } else if (j == 2) roff(" one or two"); else { (void) sprintf(temp, " up to %ld", j); roff(temp); } #ifdef ATARIST_MWC if (rcmove & (holder = CM_CARRY_OBJ)) #else if (rcmove & CM_CARRY_OBJ) #endif { roff(p); #ifdef ATARIST_MWC if (rcmove & (holder = CM_CARRY_GOLD)) #else if (rcmove & CM_CARRY_GOLD) #endif { roff(" or treasure"); if (j > 1) roff("s"); } roff("."); } else if (j != 1) roff(" treasures."); else roff(" treasure."); } /* We know about attacks it has used on us, and maybe the damage they do. */ /* k is the total number of known attacks, used for punctuation */ k = 0; for (j = 0; j < 4; j++) /* Turbo C needs a 16 bit int for the array index. */ if (mp->r_attacks[(int)j]) k++; pu = cp->damage; /* j counts the attacks as printed, used for punctuation */ j = 0; for (i = 0; *pu != 0 && i < 4; pu++, i++) { int att_type, att_how, d1, d2; /* don't print out unknown attacks */ if (!mp->r_attacks[i]) continue; att_type = monster_attacks[*pu].attack_type; att_how = monster_attacks[*pu].attack_desc; d1 = monster_attacks[*pu].attack_dice; d2 = monster_attacks[*pu].attack_sides; j++; if (j == 1) roff(" It can "); else if (j == k) roff(", and "); else roff(", "); if (att_how > 19) att_how = 0; roff(desc_amethod[att_how]); if (att_type != 1 || d1 > 0 && d2 > 0) { roff(" to "); if (att_type > 24) att_type = 0; roff(desc_atype[att_type]); if (d1 && d2) { if (knowdamage(cp->level, mp->r_attacks[i], d1*d2)) { if (att_type == 19) /* Loss of experience */ roff(" by"); else roff(" with damage"); (void) sprintf(temp, " %dd%d", d1, d2 ); roff(temp); } } } } if (j) roff("."); else if (k > 0 && mp->r_attacks[0] >= 10) roff(" It has no physical attacks."); else roff(" Nothing is known about its attack."); /* Always know the win creature. */ #ifdef ATARIST_MWC if (cp->cmove & (holder = CM_WIN)) #else if (cp->cmove & CM_WIN) #endif roff(" Killing one of these wins the game!"); roff("\n"); prt("--pause--", roffpline, 0); if (wizard) *mp = save_mem; return inkey(); } /* Print out strings, filling up lines as we go. */ static void roff(p) register char *p; { register char *q, *r; while (*p) { *roffp = *p; if (*p == '\n' || roffp >= roffbuf + sizeof(roffbuf)-1) { q = roffp; if (*p != '\n') while (*q != ' ') q--; *q = 0; prt(roffbuf, roffpline, 0); roffpline++; r = roffbuf; while (q < roffp) { q++; *r = *q; r++; } roffp = r; } else roffp++; p++; } } moria-5.6.debian.1/source/staffs.c0000644000175000017500000001064211074756544015135 0ustar pjbpjb/* source/staffs.c: staff code Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #ifdef USG #include #else #include #endif /* Use a staff. -RAK- */ void use() { int32u i; int j, k, item_val, chance, y, x; register int ident; register struct misc *m_ptr; register inven_type *i_ptr; free_turn_flag = TRUE; if (inven_ctr == 0) msg_print("But you are not carrying anything."); else if (!find_range(TV_STAFF, TV_NEVER, &j, &k)) msg_print("You are not carrying any staffs."); else if (get_item(&item_val, "Use which staff?", j, k, CNIL, CNIL)) { i_ptr = &inventory[item_val]; free_turn_flag = FALSE; m_ptr = &py.misc; chance = m_ptr->save + stat_adj(A_INT) - (int)i_ptr->level - 5 + (class_level_adj[m_ptr->pclass][CLA_DEVICE] * m_ptr->lev / 3); if (py.flags.confused > 0) chance = chance / 2; if ((chance < USE_DEVICE) && (randint(USE_DEVICE - chance + 1) == 1)) chance = USE_DEVICE; /* Give everyone a slight chance */ if (chance <= 0) chance = 1; if (randint(chance) < USE_DEVICE) msg_print("You failed to use the staff properly."); else if (i_ptr->p1 > 0) { i = i_ptr->flags; ident = FALSE; (i_ptr->p1)--; while (i != 0) { j = bit_pos(&i) + 1; /* Staffs. */ switch(j) { case 1: ident = light_area(char_row, char_col); break; case 2: ident = detect_sdoor(); break; case 3: ident = detect_trap(); break; case 4: ident = detect_treasure(); break; case 5: ident = detect_object(); break; case 6: teleport(100); ident = TRUE; break; case 7: ident = TRUE; earthquake(); break; case 8: ident = FALSE; for (k = 0; k < randint(4); k++) { y = char_row; x = char_col; ident |= summon_monster(&y, &x, FALSE); } break; case 10: ident = TRUE; destroy_area(char_row, char_col); break; case 11: ident = TRUE; starlite(char_row, char_col); break; case 12: ident = speed_monsters(1); break; case 13: ident = speed_monsters(-1); break; case 14: ident = sleep_monsters2(); break; case 15: ident = hp_player(randint(8)); break; case 16: ident = detect_invisible(); break; case 17: if (py.flags.fast == 0) ident = TRUE; py.flags.fast += randint(30) + 15; break; case 18: if (py.flags.slow == 0) ident = TRUE; py.flags.slow += randint(30) + 15; break; case 19: ident = mass_poly(); break; case 20: if (remove_curse()) { if (py.flags.blind < 1) msg_print("The staff glows blue for a moment.."); ident = TRUE; } break; case 21: ident = detect_evil(); break; case 22: if ((cure_blindness()) || (cure_poison()) || (cure_confusion())) ident = TRUE; break; case 23: ident = dispel_creature(CD_EVIL, 60); break; case 25: ident = unlight_area(char_row, char_col); break; case 32: /* store bought flag */ break; default: msg_print("Internal error in staffs()"); break; } /* End of staff actions. */ } if (ident) { if (!known1_p(i_ptr)) { m_ptr = &py.misc; /* round half-way case up */ m_ptr->exp += (i_ptr->level + (m_ptr->lev >> 1)) / m_ptr->lev; prt_experience(); identify(&item_val); i_ptr = &inventory[item_val]; } } else if (!known1_p(i_ptr)) sample (i_ptr); desc_charges(item_val); } else { msg_print("The staff has no charges left."); if (!known2_p(i_ptr)) add_inscribe(i_ptr, ID_EMPTY); } } } moria-5.6.debian.1/source/misc3.c0000644000175000017500000016542611074756544014700 0ustar pjbpjb/* source/misc3.c: misc code for maintaining the dungeon, printing player info Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include #include "config.h" #include "constant.h" #include "types.h" #include "externs.h" #include #ifndef USG #include #include #endif #ifdef USG #ifndef ATARIST_MWC #include #else char *index(); #endif #else #include #endif #if defined(LINT_ARGS) static void prt_lnum(char *, int32, int, int); static void prt_7lnum(char *, int32, int, int); static void prt_num(char *, int, int, int); static void prt_long(int32, int, int); static void prt_int(int, int, int); static void gain_level(void); #endif static char *stat_names[] = { "STR : ", "INT : ", "WIS : ", "DEX : ", "CON : ", "CHR : " }; #define BLANK_LENGTH 24 static char blank_string[] = " "; /* Places a particular trap at location y, x -RAK- */ void place_trap(y, x, subval) int y, x, subval; { register int cur_pos; cur_pos = popt(); cave[y][x].tptr = cur_pos; invcopy(&t_list[cur_pos], OBJ_TRAP_LIST + subval); } /* Places rubble at location y, x -RAK- */ void place_rubble(y, x) int y, x; { register int cur_pos; register cave_type *cave_ptr; cur_pos = popt(); cave_ptr = &cave[y][x]; cave_ptr->tptr = cur_pos; cave_ptr->fval = BLOCKED_FLOOR; invcopy(&t_list[cur_pos], OBJ_RUBBLE); } /* Places a treasure (Gold or Gems) at given row, column -RAK- */ void place_gold(y, x) int y, x; { register int i, cur_pos; #ifdef M_XENIX /* Avoid 'register' bug. */ inven_type *t_ptr; #else register inven_type *t_ptr; #endif cur_pos = popt(); i = ((randint(dun_level+2)+2) / 2) - 1; if (randint(OBJ_GREAT) == 1) i += randint(dun_level+1); if (i >= MAX_GOLD) i = MAX_GOLD - 1; cave[y][x].tptr = cur_pos; invcopy(&t_list[cur_pos], OBJ_GOLD_LIST+i); t_ptr = &t_list[cur_pos]; t_ptr->cost += (8L * (long)randint((int)t_ptr->cost)) + randint(8); if (cave[y][x].cptr == 1) msg_print ("You feel something roll beneath your feet."); } /* Returns the array number of a random object -RAK- */ int get_obj_num(level,must_be_small) int level,must_be_small; { register int i, j; if (level == 0) i = randint(t_level[0]) - 1; else { if (level >= MAX_OBJ_LEVEL) level = MAX_OBJ_LEVEL; else if (randint(OBJ_GREAT) == 1) { level = level * MAX_OBJ_LEVEL / randint (MAX_OBJ_LEVEL) + 1; if (level > MAX_OBJ_LEVEL) level = MAX_OBJ_LEVEL; } /* This code has been added to make it slightly more likely to get the higher level objects. Originally a uniform distribution over all objects less than or equal to the dungeon level. This distribution makes a level n objects occur approx 2/n% of the time on level n, and 1/2n are 0th level. */ do { if (randint(2) == 1) i = randint(t_level[level]) - 1; else /* Choose three objects, pick the highest level. */ { i = randint(t_level[level]) - 1; j = randint(t_level[level]) - 1; if (i < j) i = j; j = randint(t_level[level]) - 1; if (i < j) i = j; j = object_list[sorted_objects[i]].level; if (j == 0) i = randint(t_level[0]) - 1; else i = randint(t_level[j]-t_level[j-1]) - 1 + t_level[j-1]; } } while ((must_be_small) && (set_large(&object_list[sorted_objects[i]]))); } return(i); } /* Places an object at given row, column co-ordinate -RAK- */ void place_object(y, x, must_be_small) int y, x, must_be_small; { register int cur_pos, tmp; cur_pos = popt(); cave[y][x].tptr = cur_pos; /* split this line up to avoid a reported compiler bug */ tmp = get_obj_num(dun_level, must_be_small); invcopy(&t_list[cur_pos], sorted_objects[tmp]); magic_treasure(cur_pos, dun_level); if (cave[y][x].cptr == 1) msg_print ("You feel something roll beneath your feet."); /* -CJS- */ } /* Allocates an object for tunnels and rooms -RAK- */ void alloc_object(alloc_set, typ, num) int (*alloc_set)(); int typ, num; { register int i, j, k; for (k = 0; k < num; k++) { do { i = randint(cur_height) - 1; j = randint(cur_width) - 1; } /* don't put an object beneath the player, this could cause problems if player is standing under rubble, or on a trap */ while ((!(*alloc_set)(cave[i][j].fval)) || (cave[i][j].tptr != 0) || (i == char_row && j == char_col)); if (typ < 4) { /* typ == 2 not used, used to be visible traps */ if (typ == 1) place_trap(i, j, randint(MAX_TRAP)-1); /* typ == 1 */ else place_rubble(i, j); /* typ == 3 */ } else { if (typ == 4) place_gold(i, j); /* typ == 4 */ else place_object(i, j, FALSE); /* typ == 5 */ } } } /* Creates objects nearby the coordinates given -RAK- */ void random_object(y, x, num) int y, x, num; { register int i, j, k; register cave_type *cave_ptr; do { i = 0; do { j = y - 3 + randint(5); k = x - 4 + randint(7); cave_ptr = &cave[j][k]; if (in_bounds(j, k) && (cave_ptr->fval <= MAX_CAVE_FLOOR) && (cave_ptr->tptr == 0)) { if (randint(100) < 75) place_object(j, k, FALSE); else place_gold(j, k); i = 9; } i++; } while(i <= 10); num--; } while (num != 0); } /* Converts stat num into string -RAK- */ void cnv_stat(stat, out_val) int8u stat; char *out_val; { register int part1, part2; if (stat > 18) { part1 = 18; part2 = stat - 18; if (part2 == 100) (void) strcpy(out_val, "18/100"); else (void) sprintf(out_val, " %2d/%02d", part1, part2); } else (void) sprintf(out_val, "%6d", stat); } /* Print character stat in given row, column -RAK- */ void prt_stat(stat) int stat; { stat_type out_val1; cnv_stat(py.stats.use_stat[stat], out_val1); put_buffer(stat_names[stat], 6+stat, STAT_COLUMN); put_buffer (out_val1, 6+stat, STAT_COLUMN+6); } /* Print character info in given row, column -RAK- */ /* the longest title is 13 characters, so only pad to 13 */ void prt_field(info, row, column) char *info; int row, column; { put_buffer (&blank_string[BLANK_LENGTH-13], row, column); put_buffer (info, row, column); } /* Print long number with header at given row, column */ static void prt_lnum(header, num, row, column) char *header; int32 num; int row, column; { vtype out_val; (void) sprintf(out_val, "%s: %6ld", header, num); put_buffer(out_val, row, column); } /* Print long number (7 digits of space) with header at given row, column */ static void prt_7lnum(header, num, row, column) char *header; int32 num; int row, column; { vtype out_val; (void) sprintf(out_val, "%s: %7ld", header, num); put_buffer(out_val, row, column); } /* Print number with header at given row, column -RAK- */ static void prt_num(header, num, row, column) char *header; int num, row, column; { vtype out_val; (void) sprintf(out_val, "%s: %6d", header, num); put_buffer(out_val, row, column); } /* Print long number at given row, column */ static void prt_long(num, row, column) int32 num; int row, column; { vtype out_val; (void) sprintf(out_val, "%6ld", num); put_buffer(out_val, row, column); } /* Print number at given row, column -RAK- */ static void prt_int(num, row, column) int num, row, column; { vtype out_val; (void) sprintf(out_val, "%6d", num); put_buffer(out_val, row, column); } /* Adjustment for wisdom/intelligence -JWT- */ int stat_adj(stat) int stat; { register int value; value = py.stats.use_stat[stat]; if (value > 117) return(7); else if (value > 107) return(6); else if (value > 87) return(5); else if (value > 67) return(4); else if (value > 17) return(3); else if (value > 14) return(2); else if (value > 7) return(1); else return(0); } /* Adjustment for charisma -RAK- */ /* Percent decrease or increase in price of goods */ int chr_adj() { register int charisma; charisma = py.stats.use_stat[A_CHR]; if (charisma > 117) return(90); else if (charisma > 107) return(92); else if (charisma > 87) return(94); else if (charisma > 67) return(96); else if (charisma > 18) return(98); else switch(charisma) { case 18: return(100); case 17: return(101); case 16: return(102); case 15: return(103); case 14: return(104); case 13: return(106); case 12: return(108); case 11: return(110); case 10: return(112); case 9: return(114); case 8: return(116); case 7: return(118); case 6: return(120); case 5: return(122); case 4: return(125); case 3: return(130); default: return(100); } } /* Returns a character's adjustment to hit points -JWT- */ int con_adj() { register int con; con = py.stats.use_stat[A_CON]; if (con < 7) return(con - 7); else if (con < 17) return(0); else if (con == 17) return(1); else if (con < 94) return(2); else if (con < 117) return(3); else return(4); } char *title_string() { register char *p; if (py.misc.lev < 1) p = "Babe in arms"; else if (py.misc.lev <= MAX_PLAYER_LEVEL) p = player_title[py.misc.pclass][py.misc.lev-1]; else if (py.misc.male) p = "**KING**"; else p = "**QUEEN**"; return p; } /* Prints title of character -RAK- */ void prt_title() { prt_field(title_string(), 4, STAT_COLUMN); } /* Prints level -RAK- */ void prt_level() { prt_int((int)py.misc.lev, 13, STAT_COLUMN+6); } /* Prints players current mana points. -RAK- */ void prt_cmana() { prt_int(py.misc.cmana, 15, STAT_COLUMN+6); } /* Prints Max hit points -RAK- */ void prt_mhp() { prt_int(py.misc.mhp, 16, STAT_COLUMN+6); } /* Prints players current hit points -RAK- */ void prt_chp() { prt_int(py.misc.chp, 17, STAT_COLUMN+6); } /* prints current AC -RAK- */ void prt_pac() { prt_int(py.misc.dis_ac, 19, STAT_COLUMN+6); } /* Prints current gold -RAK- */ void prt_gold() { prt_long(py.misc.au, 20, STAT_COLUMN+6); } /* Prints depth in stat area -RAK- */ void prt_depth() { vtype depths; register int depth; depth = dun_level*50; if (depth == 0) (void) strcpy(depths, "Town level"); else (void) sprintf(depths, "%d feet", depth); prt(depths, 23, 65); } /* Prints status of hunger -RAK- */ void prt_hunger() { if (PY_WEAK & py.flags.status) put_buffer("Weak ", 23, 0); else if (PY_HUNGRY & py.flags.status) put_buffer("Hungry", 23, 0); else put_buffer(&blank_string[BLANK_LENGTH-6], 23, 0); } /* Prints Blind status -RAK- */ void prt_blind() { if (PY_BLIND & py.flags.status) put_buffer("Blind", 23, 7); else put_buffer(&blank_string[BLANK_LENGTH-5], 23, 7); } /* Prints Confusion status -RAK- */ void prt_confused() { if (PY_CONFUSED & py.flags.status) put_buffer("Confused", 23, 13); else put_buffer(&blank_string[BLANK_LENGTH-8], 23, 13); } /* Prints Fear status -RAK- */ void prt_afraid() { if (PY_FEAR & py.flags.status) put_buffer("Afraid", 23, 22); else put_buffer(&blank_string[BLANK_LENGTH-6], 23, 22); } /* Prints Poisoned status -RAK- */ void prt_poisoned() { if (PY_POISONED & py.flags.status) put_buffer("Poisoned", 23, 29); else put_buffer(&blank_string[BLANK_LENGTH-8], 23, 29); } /* Prints Searching, Resting, Paralysis, or 'count' status -RAK- */ void prt_state() { char tmp[16]; #ifdef ATARIST_MWC int32u holder; #endif #ifdef ATARIST_MWC py.flags.status &= ~(holder = PY_REPEAT); #else py.flags.status &= ~PY_REPEAT; #endif if (py.flags.paralysis > 1) put_buffer ("Paralysed", 23, 38); else if (PY_REST & py.flags.status) { if (py.flags.rest < 0) (void) strcpy (tmp, "Rest *"); else if (display_counts) (void) sprintf (tmp, "Rest %-5d", py.flags.rest); else (void) strcpy (tmp, "Rest"); put_buffer (tmp, 23, 38); } else if (command_count > 0) { if (display_counts) (void) sprintf (tmp, "Repeat %-3d", command_count); else (void) strcpy (tmp, "Repeat"); #ifdef ATARIST_MWC py.flags.status |= holder; #else py.flags.status |= PY_REPEAT; #endif put_buffer (tmp, 23, 38); if (PY_SEARCH & py.flags.status) put_buffer ("Search", 23, 38); } else if (PY_SEARCH & py.flags.status) put_buffer("Searching", 23, 38); else /* "repeat 999" is 10 characters */ put_buffer(&blank_string[BLANK_LENGTH-10], 23, 38); } /* Prints the speed of a character. -CJS- */ void prt_speed () { register int i; i = py.flags.speed; if (PY_SEARCH & py.flags.status) /* Search mode. */ i--; if (i > 1) put_buffer ("Very Slow", 23, 49); else if (i == 1) put_buffer ("Slow ", 23, 49); else if (i == 0) put_buffer (&blank_string[BLANK_LENGTH-9], 23, 49); else if (i == -1) put_buffer ("Fast ", 23, 49); else put_buffer ("Very Fast", 23, 49); } void prt_study() { #ifdef ATARIST_MWC int32u holder; #endif #ifdef ATARIST_MWC py.flags.status &= ~(holder = PY_STUDY); #else py.flags.status &= ~PY_STUDY; #endif if (py.flags.new_spells == 0) put_buffer (&blank_string[BLANK_LENGTH-5], 23, 59); else put_buffer ("Study", 23, 59); } /* Prints winner status on display -RAK- */ void prt_winner() { if (noscore & 0x2) { if (wizard) put_buffer("Is wizard ", 22, 0); else put_buffer("Was wizard ", 22, 0); } else if (noscore & 0x1) put_buffer("Resurrected", 22, 0); else if (noscore & 0x4) put_buffer ("Duplicate", 22, 0); else if (total_winner) put_buffer("*Winner* ", 22, 0); } int8u modify_stat (stat, amount) int stat; int16 amount; { register int loop, i; register int8u tmp_stat; tmp_stat = py.stats.cur_stat[stat]; loop = (amount < 0 ? -amount : amount); for (i = 0; i < loop; i++) { if (amount > 0) { if (tmp_stat < 18) tmp_stat++; else if (tmp_stat < 108) tmp_stat += 10; else tmp_stat = 118; } else { if (tmp_stat > 27) tmp_stat -= 10; else if (tmp_stat > 18) tmp_stat = 18; else if (tmp_stat > 3) tmp_stat--; } } return tmp_stat; } /* Set the value of the stat which is actually used. -CJS- */ void set_use_stat(stat) int stat; { #ifdef ATARIST_MWC int32u holder; #endif py.stats.use_stat[stat] = modify_stat (stat, py.stats.mod_stat[stat]); if (stat == A_STR) { #ifdef ATARIST_MWC py.flags.status |= (holder = PY_STR_WGT); #else py.flags.status |= PY_STR_WGT; #endif calc_bonuses(); } else if (stat == A_DEX) calc_bonuses(); else if (stat == A_INT && class[py.misc.pclass].spell == MAGE) { calc_spells(A_INT); calc_mana(A_INT); } else if (stat == A_WIS && class[py.misc.pclass].spell == PRIEST) { calc_spells(A_WIS); calc_mana(A_WIS); } else if (stat == A_CON) calc_hitpoints(); } /* Increases a stat by one randomized level -RAK- */ int inc_stat(stat) register int stat; { register int tmp_stat, gain; tmp_stat = py.stats.cur_stat[stat]; if (tmp_stat < 118) { if (tmp_stat < 18) tmp_stat++; else if (tmp_stat < 116) { /* stat increases by 1/6 to 1/3 of difference from max */ gain = ((118 - tmp_stat)/3 + 1) >> 1; tmp_stat += randint(gain) + gain; } else tmp_stat++; py.stats.cur_stat[stat] = tmp_stat; if (tmp_stat > py.stats.max_stat[stat]) py.stats.max_stat[stat] = tmp_stat; set_use_stat (stat); prt_stat (stat); return TRUE; } else return FALSE; } /* Decreases a stat by one randomized level -RAK- */ int dec_stat(stat) register int stat; { register int tmp_stat, loss; tmp_stat = py.stats.cur_stat[stat]; if (tmp_stat > 3) { if (tmp_stat < 19) tmp_stat--; else if (tmp_stat < 117) { loss = (((118 - tmp_stat) >> 1) + 1) >> 1; tmp_stat += -randint(loss) - loss; if (tmp_stat < 18) tmp_stat = 18; } else tmp_stat--; py.stats.cur_stat[stat] = tmp_stat; set_use_stat (stat); prt_stat (stat); return TRUE; } else return FALSE; } /* Restore a stat. Return TRUE only if this actually makes a difference. */ int res_stat (stat) int stat; { register int i; i = py.stats.max_stat[stat] - py.stats.cur_stat[stat]; if (i) { py.stats.cur_stat[stat] += i; set_use_stat (stat); prt_stat (stat); return TRUE; } return FALSE; } /* Boost a stat artificially (by wearing something). If the display argument is TRUE, then increase is shown on the screen. */ void bst_stat (stat, amount) int stat, amount; { #ifdef ATARIST_MWC int32u holder; #endif py.stats.mod_stat[stat] += amount; set_use_stat (stat); /* can not call prt_stat() here, may be in store, may be in inven_command */ #ifdef ATARIST_MWC py.flags.status |= ((holder = PY_STR) << stat); #else py.flags.status |= (PY_STR << stat); #endif } /* Returns a character's adjustment to hit. -JWT- */ int tohit_adj() { register int total, stat; stat = py.stats.use_stat[A_DEX]; if (stat < 4) total = -3; else if (stat < 6) total = -2; else if (stat < 8) total = -1; else if (stat < 16) total = 0; else if (stat < 17) total = 1; else if (stat < 18) total = 2; else if (stat < 69) total = 3; else if (stat < 118) total = 4; else total = 5; stat = py.stats.use_stat[A_STR]; if (stat < 4) total -= 3; else if (stat < 5) total -= 2; else if (stat < 7) total -= 1; else if (stat < 18) total -= 0; else if (stat < 94) total += 1; else if (stat < 109) total += 2; else if (stat < 117) total += 3; else total += 4; return(total); } /* Returns a character's adjustment to armor class -JWT- */ int toac_adj() { register int stat; stat = py.stats.use_stat[A_DEX]; if (stat < 4) return(-4); else if (stat == 4) return(-3); else if (stat == 5) return(-2); else if (stat == 6) return(-1); else if (stat < 15) return( 0); else if (stat < 18) return( 1); else if (stat < 59) return( 2); else if (stat < 94) return( 3); else if (stat < 117) return( 4); else return( 5); } /* Returns a character's adjustment to disarm -RAK- */ int todis_adj() { register int stat; stat = py.stats.use_stat[A_DEX]; if (stat < 4) return(-8); else if (stat == 4) return(-6); else if (stat == 5) return(-4); else if (stat == 6) return(-2); else if (stat == 7) return(-1); else if (stat < 13) return( 0); else if (stat < 16) return( 1); else if (stat < 18) return( 2); else if (stat < 59) return( 4); else if (stat < 94) return( 5); else if (stat < 117) return( 6); else return( 8); } /* Returns a character's adjustment to damage -JWT- */ int todam_adj() { register int stat; stat = py.stats.use_stat[A_STR]; if (stat < 4) return(-2); else if (stat < 5) return(-1); else if (stat < 16) return( 0); else if (stat < 17) return( 1); else if (stat < 18) return( 2); else if (stat < 94) return( 3); else if (stat < 109) return( 4); else if (stat < 117) return( 5); else return( 6); } /* Prints character-screen info -RAK- */ void prt_stat_block() { register int32u status; register struct misc *m_ptr; register int i; m_ptr = &py.misc; prt_field(race[py.misc.prace].trace, 2, STAT_COLUMN); prt_field(class[py.misc.pclass].title, 3, STAT_COLUMN); prt_field(title_string(), 4, STAT_COLUMN); for (i = 0; i < 6; i++) prt_stat (i); prt_num ("LEV ", (int)m_ptr->lev, 13, STAT_COLUMN); prt_lnum("EXP ", m_ptr->exp, 14, STAT_COLUMN); prt_num ("MANA", m_ptr->cmana, 15, STAT_COLUMN); prt_num ("MHP ", m_ptr->mhp, 16, STAT_COLUMN); prt_num ("CHP ", m_ptr->chp, 17, STAT_COLUMN); prt_num ("AC ", m_ptr->dis_ac, 19, STAT_COLUMN); prt_lnum("GOLD", m_ptr->au, 20, STAT_COLUMN); prt_winner(); status = py.flags.status; if ((PY_HUNGRY|PY_WEAK) & status) prt_hunger(); if (PY_BLIND & status) prt_blind(); if (PY_CONFUSED & status) prt_confused(); if (PY_FEAR & status) prt_afraid(); if (PY_POISONED & status) prt_poisoned(); if ((PY_SEARCH|PY_REST) & status) prt_state (); /* if speed non zero, print it, modify speed if Searching */ if (py.flags.speed - ((PY_SEARCH & status) >> 8) != 0) prt_speed (); /* display the study field */ prt_study(); } /* Draws entire screen -RAK- */ void draw_cave() { clear_screen (); prt_stat_block(); prt_map(); prt_depth(); } /* Prints the following information on the screen. -JWT- */ void put_character() { register struct misc *m_ptr; m_ptr = &py.misc; clear_screen (); put_buffer ("Name :", 2, 1); put_buffer ("Race :", 3, 1); put_buffer ("Sex :", 4, 1); put_buffer ("Class :", 5, 1); if (character_generated) { put_buffer (m_ptr->name, 2, 15); put_buffer (race[m_ptr->prace].trace, 3, 15); put_buffer ((m_ptr->male ? "Male" : "Female"), 4, 15); put_buffer (class[m_ptr->pclass].title, 5, 15); } } /* Prints the following information on the screen. -JWT- */ void put_stats() { register struct misc *m_ptr; register int i; vtype buf; m_ptr = &py.misc; for (i = 0; i < 6; i++) { cnv_stat (py.stats.use_stat[i], buf); put_buffer (stat_names[i], 2+i, 61); put_buffer (buf, 2+i, 66); if (py.stats.max_stat[i] > py.stats.cur_stat[i]) { cnv_stat (py.stats.max_stat[i], buf); put_buffer (buf, 2+i, 73); } } prt_num("+ To Hit ", m_ptr->dis_th, 9, 1); prt_num("+ To Damage ", m_ptr->dis_td, 10, 1); prt_num("+ To AC ", m_ptr->dis_tac, 11, 1); prt_num(" Total AC ", m_ptr->dis_ac, 12, 1); } /* Returns a rating of x depending on y -JWT- */ char *likert(x, y) int x, y; { switch((x/y)) { case -3: case -2: case -1: return("Very Bad"); case 0: case 1: return("Bad"); case 2: return("Poor"); case 3: case 4: return("Fair"); case 5: return("Good"); case 6: return("Very Good"); case 7: case 8: return("Excellent"); default: return("Superb"); } } /* Prints age, height, weight, and SC -JWT- */ void put_misc1() { register struct misc *m_ptr; m_ptr = &py.misc; prt_num("Age ", (int)m_ptr->age, 2, 38); prt_num("Height ", (int)m_ptr->ht, 3, 38); prt_num("Weight ", (int)m_ptr->wt, 4, 38); prt_num("Social Class ", (int)m_ptr->sc, 5, 38); } /* Prints the following information on the screen. -JWT- */ void put_misc2() { register struct misc *m_ptr; m_ptr = &py.misc; prt_7lnum("Level ", (int32)m_ptr->lev, 9, 28); prt_7lnum("Experience ", m_ptr->exp, 10, 28); prt_7lnum("Max Exp ", m_ptr->max_exp, 11, 28); if (m_ptr->lev >= MAX_PLAYER_LEVEL) prt ("Exp to Adv.: *******", 12, 28); else prt_7lnum("Exp to Adv.", (int32)(player_exp[m_ptr->lev-1] * m_ptr->expfact / 100), 12, 28); prt_7lnum("Gold ", m_ptr->au, 13, 28); prt_num("Max Hit Points ", m_ptr->mhp, 9, 52); prt_num("Cur Hit Points ", m_ptr->chp, 10, 52); prt_num("Max Mana ", m_ptr->mana, 11, 52); prt_num("Cur Mana ", m_ptr->cmana, 12, 52); } /* Prints ratings on certain abilities -RAK- */ void put_misc3() { int xbth, xbthb, xfos, xsrh, xstl, xdis, xsave, xdev; vtype xinfra; register struct misc *p_ptr; clear_from(14); p_ptr = &py.misc; xbth = p_ptr->bth + p_ptr->ptohit*BTH_PLUS_ADJ + (class_level_adj[p_ptr->pclass][CLA_BTH] * p_ptr->lev); xbthb = p_ptr->bthb + p_ptr->ptohit*BTH_PLUS_ADJ + (class_level_adj[p_ptr->pclass][CLA_BTHB] * p_ptr->lev); /* this results in a range from 0 to 29 */ xfos = 40 - p_ptr->fos; if (xfos < 0) xfos = 0; xsrh = p_ptr->srh; /* this results in a range from 0 to 9 */ xstl = p_ptr->stl + 1; xdis = p_ptr->disarm + 2*todis_adj() + stat_adj(A_INT) + (class_level_adj[p_ptr->pclass][CLA_DISARM] * p_ptr->lev / 3); xsave = p_ptr->save + stat_adj(A_WIS) + (class_level_adj[p_ptr->pclass][CLA_SAVE] * p_ptr->lev / 3); xdev = p_ptr->save + stat_adj(A_INT) + (class_level_adj[p_ptr->pclass][CLA_DEVICE] * p_ptr->lev / 3); (void) sprintf(xinfra, "%d feet", py.flags.see_infra*10); put_buffer ("(Miscellaneous Abilities)", 15, 25); put_buffer ("Fighting :", 16, 1); put_buffer (likert (xbth, 12), 16, 15); put_buffer ("Bows/Throw :", 17, 1); put_buffer (likert (xbthb, 12), 17, 15); put_buffer ("Saving Throw:", 18, 1); put_buffer (likert (xsave, 6), 18, 15); put_buffer ("Stealth :", 16, 28); put_buffer (likert (xstl, 1), 16, 42); put_buffer ("Disarming :", 17, 28); put_buffer (likert (xdis, 8), 17, 42); put_buffer ("Magic Device:", 18, 28); put_buffer (likert (xdev, 6), 18, 42); put_buffer ("Perception :", 16, 55); put_buffer (likert (xfos, 3), 16, 69); put_buffer ("Searching :", 17, 55); put_buffer (likert (xsrh, 6), 17, 69); put_buffer ("Infra-Vision:", 18, 55); put_buffer (xinfra, 18, 69); } /* Used to display the character on the screen. -RAK- */ void display_char() { put_character(); put_misc1(); put_stats(); put_misc2(); put_misc3(); } /* Gets a name for the character -JWT- */ void get_name() { prt("Enter your player's name [press when finished]", 21, 2); put_buffer (&blank_string[BLANK_LENGTH-23], 2, 15); #if defined(MAC) || defined(AMIGA) /* Force player to give a name, would be nice to get name from chooser (STR -16096), but that name might be too long */ while (!get_string(py.misc.name, 2, 15, 23) || py.misc.name[0] == 0); #else if (!get_string(py.misc.name, 2, 15, 23) || py.misc.name[0] == 0) { user_name (py.misc.name); put_buffer (py.misc.name, 2, 15); } #endif clear_from (20); #ifdef MAC /* Use the new name to set save file default name. */ initsavedefaults(); #endif } /* Changes the name of the character -JWT- */ void change_name() { register char c; register int flag; #ifndef MAC vtype temp; #endif flag = FALSE; display_char(); do { prt( "ile character description. hange character name.", 21, 2); c = inkey(); switch(c) { case 'c': get_name(); flag = TRUE; break; case 'f': #ifdef MAC /* On mac, file_character() gets filename with std file dialog. */ if (file_character ()) flag = TRUE; #else prt ("File name:", 0, 0); if (get_string (temp, 0, 10, 60) && temp[0]) if (file_character (temp)) flag = TRUE; #endif break; case ESCAPE: case ' ': case '\n': case '\r': flag = TRUE; break; default: bell (); break; } } while (!flag); } /* Destroy an item in the inventory -RAK- */ void inven_destroy(item_val) int item_val; { register int j; register inven_type *i_ptr; #ifdef ATARIST_MWC int32u holder; #endif i_ptr = &inventory[item_val]; if ((i_ptr->number > 1) && (i_ptr->subval <= ITEM_SINGLE_STACK_MAX)) { i_ptr->number--; inven_weight -= i_ptr->weight; } else { inven_weight -= i_ptr->weight*i_ptr->number; for (j = item_val; j < inven_ctr-1; j++) inventory[j] = inventory[j+1]; invcopy(&inventory[inven_ctr-1], OBJ_NOTHING); inven_ctr--; } #ifdef ATARIST_MWC py.flags.status |= (holder = PY_STR_WGT); #else py.flags.status |= PY_STR_WGT; #endif } /* Copies the object in the second argument over the first argument. However, the second always gets a number of one except for ammo etc. */ void take_one_item (s_ptr, i_ptr) register inven_type *s_ptr, *i_ptr; { *s_ptr = *i_ptr; if ((s_ptr->number > 1) && (s_ptr->subval >= ITEM_SINGLE_STACK_MIN) && (s_ptr->subval <= ITEM_SINGLE_STACK_MAX)) s_ptr->number = 1; } /* Drops an item from inventory to given location -RAK- */ void inven_drop(item_val, drop_all) register int item_val, drop_all; { int i; register inven_type *i_ptr; bigvtype prt1, prt2; #ifdef ATARIST_MWC int32u holder; #endif if (cave[char_row][char_col].tptr != 0) (void) delete_object(char_row, char_col); i = popt (); i_ptr = &inventory[item_val]; t_list[i] = *i_ptr; cave[char_row][char_col].tptr = i; if (item_val >= INVEN_WIELD) takeoff (item_val, -1); else { if (drop_all || i_ptr->number == 1) { inven_weight -= i_ptr->weight*i_ptr->number; inven_ctr--; while (item_val < inven_ctr) { inventory[item_val] = inventory[item_val+1]; item_val++; } invcopy(&inventory[inven_ctr], OBJ_NOTHING); } else { t_list[i].number = 1; inven_weight -= i_ptr->weight; i_ptr->number--; } objdes (prt1, &t_list[i], TRUE); (void) sprintf (prt2, "Dropped %s", prt1); msg_print (prt2); } #ifdef ATARIST_MWC py.flags.status |= (holder = PY_STR_WGT); #else py.flags.status |= PY_STR_WGT; #endif } /* Destroys a type of item on a given percent chance -RAK- */ int inven_damage(typ, perc) int (*typ)(); register int perc; { register int i, j; j = 0; for (i = 0; i < inven_ctr; i++) if ((*typ)(&inventory[i]) && (randint(100) < perc)) { inven_destroy(i); j++; } return(j); } /* Computes current weight limit -RAK- */ int weight_limit() { register int weight_cap; weight_cap = py.stats.use_stat[A_STR] * PLAYER_WEIGHT_CAP + py.misc.wt; if (weight_cap > 3000) weight_cap = 3000; return(weight_cap); } /* this code must be identical to the inven_carry() code below */ int inven_check_num (t_ptr) register inven_type *t_ptr; { register int i; if (inven_ctr < INVEN_WIELD) return TRUE; else if (t_ptr->subval >= ITEM_SINGLE_STACK_MIN) for (i = 0; i < inven_ctr; i++) if (inventory[i].tval == t_ptr->tval && inventory[i].subval == t_ptr->subval && /* make sure the number field doesn't overflow */ ((int)inventory[i].number + (int)t_ptr->number < 256) && /* they always stack (subval < 192), or else they have same p1 */ ((t_ptr->subval < ITEM_GROUP_MIN) || (inventory[i].p1 == t_ptr->p1)) /* only stack if both or neither are identified */ && (known1_p(&inventory[i]) == known1_p(t_ptr))) return TRUE; return FALSE; } /* return FALSE if picking up an object would change the players speed */ int inven_check_weight(i_ptr) register inven_type *i_ptr; { register int i, new_inven_weight; i = weight_limit(); new_inven_weight = i_ptr->number*i_ptr->weight + inven_weight; if (i < new_inven_weight) i = new_inven_weight / (i + 1); else i = 0; if (pack_heavy != i) return FALSE; else return TRUE; } /* Are we strong enough for the current pack and weapon? -CJS- */ void check_strength() { register int i; register inven_type *i_ptr; #ifdef ATARIST_MWC int32u holder; #endif i_ptr = &inventory[INVEN_WIELD]; if (i_ptr->tval != TV_NOTHING && (py.stats.use_stat[A_STR]*15 < i_ptr->weight)) { if (weapon_heavy == FALSE) { msg_print("You have trouble wielding such a heavy weapon."); weapon_heavy = TRUE; calc_bonuses(); } } else if (weapon_heavy == TRUE) { weapon_heavy = FALSE; if (i_ptr->tval != TV_NOTHING) msg_print("You are strong enough to wield your weapon."); calc_bonuses(); } i = weight_limit(); if (i < inven_weight) i = inven_weight / (i+1); else i = 0; if (pack_heavy != i) { if (pack_heavy < i) msg_print("Your pack is so heavy that it slows you down."); else msg_print("You move more easily under the weight of your pack."); change_speed(i - pack_heavy); pack_heavy = i; } #ifdef ATARIST_MWC py.flags.status &= ~(holder = PY_STR_WGT); #else py.flags.status &= ~PY_STR_WGT; #endif } /* Add an item to players inventory. Return the */ /* item position for a description if needed. -RAK- */ /* this code must be identical to the inven_check_num() code above */ int inven_carry(i_ptr) register inven_type *i_ptr; { register int locn, i; register int typ, subt; register inven_type *t_ptr; int known1p, always_known1p; #ifdef ATARIST_MWC int32u holder; #endif typ = i_ptr->tval; subt = i_ptr->subval; known1p = known1_p (i_ptr); always_known1p = (object_offset (i_ptr) == -1); /* Now, check to see if player can carry object */ for (locn = 0; ; locn++) { t_ptr = &inventory[locn]; if ((typ == t_ptr->tval) && (subt == t_ptr->subval) && (subt >= ITEM_SINGLE_STACK_MIN) && ((int)t_ptr->number + (int)i_ptr->number < 256) && ((subt < ITEM_GROUP_MIN) || (t_ptr->p1 == i_ptr->p1)) && /* only stack if both or neither are identified */ (known1p == known1_p(t_ptr))) { t_ptr->number += i_ptr->number; break; } /* For items which are always known1p, i.e. never have a 'color', insert them into the inventory in sorted order. */ else if ((typ == t_ptr->tval && subt < t_ptr->subval && always_known1p) || (typ > t_ptr->tval)) { for (i = inven_ctr - 1; i >= locn; i--) inventory[i+1] = inventory[i]; inventory[locn] = *i_ptr; inven_ctr++; break; } } inven_weight += i_ptr->number*i_ptr->weight; #ifdef ATARIST_MWC py.flags.status |= (holder = PY_STR_WGT); #else py.flags.status |= PY_STR_WGT; #endif return locn; } /* Returns spell chance of failure for spell -RAK- */ int spell_chance(spell) int spell; { register spell_type *s_ptr; register int chance; register int stat; s_ptr = &magic_spell[py.misc.pclass-1][spell]; chance = s_ptr->sfail - 3*(py.misc.lev-s_ptr->slevel); if (class[py.misc.pclass].spell == MAGE) stat = A_INT; else stat = A_WIS; chance -= 3 * (stat_adj(stat)-1); if (s_ptr->smana > py.misc.cmana) chance += 5 * (s_ptr->smana-py.misc.cmana); if (chance > 95) chance = 95; else if (chance < 5) chance = 5; return chance; } /* Print list of spells -RAK- */ /* if nonconsec is -1: spells numbered consecutively from 'a' to 'a'+num >=0: spells numbered by offset from nonconsec */ void print_spells(spell, num, comment, nonconsec) int *spell; register int num; int comment, nonconsec; { register int i, j; vtype out_val; register spell_type *s_ptr; int col, offset; char *p; char spell_char; if (comment) col = 22; else col = 31; offset = (class[py.misc.pclass].spell==MAGE ? SPELL_OFFSET : PRAYER_OFFSET); erase_line(1, col); put_buffer("Name", 1, col+5); put_buffer("Lv Mana Fail", 1, col+35); /* only show the first 22 choices */ if (num > 22) num = 22; for (i = 0; i < num; i++) { j = spell[i]; s_ptr = &magic_spell[py.misc.pclass-1][j]; if (comment == FALSE) p = ""; else if ((spell_forgotten & (1L << j)) != 0) p = " forgotten"; else if ((spell_learned & (1L << j)) == 0) p = " unknown"; else if ((spell_worked & (1L << j)) == 0) p = " untried"; else p = ""; /* determine whether or not to leave holes in character choices, nonconsec -1 when learning spells, consec offset>=0 when asking which spell to cast */ if (nonconsec == -1) spell_char = 'a' + i; else spell_char = 'a' + j - nonconsec; (void) sprintf(out_val, " %c) %-30s%2d %4d %3d%%%s", spell_char, spell_names[j+offset], s_ptr->slevel, s_ptr->smana, spell_chance (j), p); prt(out_val, 2+i, col); } } /* Returns spell pointer -RAK- */ int get_spell(spell, num, sn, sc, prompt, first_spell) int *spell; register int num; register int *sn, *sc; char *prompt; int first_spell; { register spell_type *s_ptr; int flag, redraw, offset, i; char choice; vtype out_str, tmp_str; *sn = -1; flag = FALSE; (void) sprintf(out_str, "(Spells %c-%c, *=List, =exit) %s", spell[0]+'a'-first_spell, spell[num-1]+'a'-first_spell, prompt); redraw = FALSE; offset = (class[py.misc.pclass].spell==MAGE ? SPELL_OFFSET : PRAYER_OFFSET); while (flag == FALSE && get_com (out_str, &choice)) { if (isupper((int)choice)) { *sn = choice-'A'+first_spell; /* verify that this is in spell[], at most 22 entries in spell[] */ for (i = 0; i < num; i++) if (*sn == spell[i]) break; if (i == num) *sn = -2; else { s_ptr = &magic_spell[py.misc.pclass-1][*sn]; (void) sprintf (tmp_str, "Cast %s (%d mana, %d%% fail)?", spell_names[*sn+offset], s_ptr->smana, spell_chance (*sn)); if (get_check (tmp_str)) flag = TRUE; else *sn = -1; } } else if (islower((int)choice)) { *sn = choice-'a'+first_spell; /* verify that this is in spell[], at most 22 entries in spell[] */ for (i = 0; i < num; i++) if (*sn == spell[i]) break; if (i == num) *sn = -2; else flag = TRUE; } else if (choice == '*') { /* only do this drawing once */ if (!redraw) { save_screen (); redraw = TRUE; print_spells (spell, num, FALSE, first_spell); } } else if (isalpha((int)choice)) *sn = -2; else { *sn = -1; bell(); } if (*sn == -2) { (void) sprintf (tmp_str, "You don't know that %s.", (offset == SPELL_OFFSET ? "spell" : "prayer")); msg_print(tmp_str); } } if (redraw) restore_screen (); erase_line(MSG_LINE, 0); if (flag) *sc = spell_chance (*sn); return(flag); } /* calculate number of spells player should have, and learn forget spells until that number is met -JEW- */ void calc_spells(stat) int stat; { register int i; register int32u mask; int32u spell_flag; int j, offset; int num_allowed, new_spells, num_known, levels; vtype tmp_str; char *p; register struct misc *p_ptr; register spell_type *msp_ptr; p_ptr = &py.misc; msp_ptr = &magic_spell[p_ptr->pclass-1][0]; if (stat == A_INT) { p = "spell"; offset = SPELL_OFFSET; } else { p = "prayer"; offset = PRAYER_OFFSET; } /* check to see if know any spells greater than level, eliminate them */ for (i = 31, mask = 0x80000000L; mask; mask >>= 1, i--) if (mask & spell_learned) { if (msp_ptr[i].slevel > p_ptr->lev) { spell_learned &= ~mask; spell_forgotten |= mask; (void) sprintf(tmp_str, "You have forgotten the %s of %s.", p, spell_names[i+offset]); msg_print(tmp_str); } else break; } /* calc number of spells allowed */ levels = p_ptr->lev - class[p_ptr->pclass].first_spell_lev + 1; switch(stat_adj(stat)) { case 0: num_allowed = 0; break; case 1: case 2: case 3: num_allowed = 1 * levels; break; case 4: case 5: num_allowed = 3 * levels / 2; break; case 6: num_allowed = 2 * levels; break; case 7: num_allowed = 5 * levels / 2; break; } num_known = 0; for (mask = 0x1; mask; mask <<= 1) if (mask & spell_learned) num_known++; new_spells = num_allowed - num_known; if (new_spells > 0) { /* remember forgotten spells while forgotten spells exist of new_spells positive, remember the spells in the order that they were learned */ for (i = 0; (spell_forgotten && new_spells && (i < num_allowed) && (i < 32)); i++) { /* j is (i+1)th spell learned */ j = spell_order[i]; /* shifting by amounts greater than number of bits in long gives an undefined result, so don't shift for unknown spells */ if (j == 99) mask = 0x0; else mask = 1L << j; if (mask & spell_forgotten) { if (msp_ptr[j].slevel <= p_ptr->lev) { new_spells--; spell_forgotten &= ~mask; spell_learned |= mask; (void) sprintf(tmp_str, "You have remembered the %s of %s.", p, spell_names[j+offset]); msg_print(tmp_str); } else num_allowed++; } } if (new_spells > 0) { /* determine which spells player can learn */ /* must check all spells here, in gain_spell() we actually check if the books are present */ spell_flag = 0x7FFFFFFFL & ~spell_learned; mask = 0x1; i = 0; for (j = 0, mask = 0x1; spell_flag; mask <<= 1, j++) if (spell_flag & mask) { spell_flag &= ~mask; if (msp_ptr[j].slevel <= p_ptr->lev) i++; } if (new_spells > i) new_spells = i; } } else if (new_spells < 0) { /* forget spells until new_spells zero or no more spells know, spells are forgotten in the opposite order that they were learned */ for (i = 31; new_spells && spell_learned; i--) { /* j is the (i+1)th spell learned */ j = spell_order[i]; /* shifting by amounts greater than number of bits in long gives an undefined result, so don't shift for unknown spells */ if (j == 99) mask = 0x0; else mask = 1L << j; if (mask & spell_learned) { spell_learned &= ~mask; spell_forgotten |= mask; new_spells++; (void) sprintf(tmp_str, "You have forgotten the %s of %s.", p, spell_names[j+offset]); msg_print(tmp_str); } } new_spells = 0; } if (new_spells != py.flags.new_spells) { if (new_spells > 0 && py.flags.new_spells == 0) { (void) sprintf(tmp_str, "You can learn some new %ss now.", p); msg_print(tmp_str); } py.flags.new_spells = new_spells; py.flags.status |= PY_STUDY; } } /* gain spells when player wants to - jw */ void gain_spells() { char query; int stat, diff_spells, new_spells; int spells[31], offset, last_known; register int i, j; register int32u spell_flag, mask; vtype tmp_str; struct misc *p_ptr; register spell_type *msp_ptr; /* Priests don't need light because they get spells from their god, so only fail when can't see if player has MAGE spells. This check is done below. */ if (py.flags.confused > 0) { msg_print("You are too confused."); return; } new_spells = py.flags.new_spells; diff_spells = 0; p_ptr = &py.misc; msp_ptr = &magic_spell[p_ptr->pclass-1][0]; if (class[p_ptr->pclass].spell == MAGE) { stat = A_INT; offset = SPELL_OFFSET; /* People with MAGE spells can't learn spells if they can't read their books. */ if (py.flags.blind > 0) { msg_print("You can't see to read your spell book!"); return; } else if (no_light()) { msg_print("You have no light to read by."); return; } } else { stat = A_WIS; offset = PRAYER_OFFSET; } for (last_known = 0; last_known < 32; last_known++) if (spell_order[last_known] == 99) break; if (!new_spells) { (void) sprintf(tmp_str, "You can't learn any new %ss!", (stat == A_INT ? "spell" : "prayer")); msg_print(tmp_str); free_turn_flag = TRUE; } else { /* determine which spells player can learn */ /* mages need the book to learn a spell, priests do not need the book */ if (stat == A_INT) { spell_flag = 0; for (i = 0; i < inven_ctr; i++) if (inventory[i].tval == TV_MAGIC_BOOK) spell_flag |= inventory[i].flags; } else spell_flag = 0x7FFFFFFF; /* clear bits for spells already learned */ spell_flag &= ~spell_learned; mask = 0x1; i = 0; for (j = 0, mask = 0x1; spell_flag; mask <<= 1, j++) if (spell_flag & mask) { spell_flag &= ~mask; if (msp_ptr[j].slevel <= p_ptr->lev) { spells[i] = j; i++; } } if (new_spells > i) { msg_print("You seem to be missing a book."); diff_spells = new_spells - i; new_spells = i; } if (new_spells == 0) ; else if (stat == A_INT) { /* get to choose which mage spells will be learned */ save_screen(); print_spells (spells, i, FALSE, -1); while (new_spells && get_com ("Learn which spell?", &query)) { j = query - 'a'; /* test j < 23 in case i is greater than 22, only 22 spells are actually shown on the screen, so limit choice to those */ if (j >= 0 && j < i && j < 22) { new_spells--; spell_learned |= 1L << spells[j]; spell_order[last_known++] = spells[j]; for (; j <= i-1; j++) spells[j] = spells[j+1]; i--; erase_line (j+1, 31); print_spells (spells, i, FALSE, -1); } else bell(); } restore_screen(); } else { /* pick a prayer at random */ while (new_spells) { j = randint(i) - 1; spell_learned |= 1L << spells[j]; spell_order[last_known++] = spells[j]; (void) sprintf (tmp_str, "You have learned the prayer of %s.", spell_names[spells[j]+offset]); msg_print(tmp_str); for (; j <= i-1; j++) spells[j] = spells[j+1]; i--; new_spells--; } } py.flags.new_spells = new_spells + diff_spells; if (py.flags.new_spells == 0) py.flags.status |= PY_STUDY; /* set the mana for first level characters when they learn their first spell */ if (py.misc.mana == 0) calc_mana(stat); } } /* Gain some mana if you know at least one spell -RAK- */ void calc_mana(stat) int stat; { register int new_mana, levels; register struct misc *p_ptr; register int32 value; #ifdef ATARIST_MWC int32u holder; #endif p_ptr = &py.misc; if (spell_learned != 0) { levels = p_ptr->lev - class[p_ptr->pclass].first_spell_lev + 1; switch(stat_adj(stat)) { case 0: new_mana = 0; break; case 1: case 2: new_mana = 1 * levels; break; case 3: new_mana = 3 * levels / 2; break; case 4: new_mana = 2 * levels; break; case 5: new_mana = 5 * levels / 2; break; case 6: new_mana = 3 * levels; break; case 7: new_mana = 4 * levels; break; } /* increment mana by one, so that first level chars have 2 mana */ if (new_mana > 0) new_mana++; /* mana can be zero when creating character */ if (p_ptr->mana != new_mana) { if (p_ptr->mana != 0) { /* change current mana proportionately to change of max mana, divide first to avoid overflow, little loss of accuracy */ value = (((long)p_ptr->cmana << 16) + p_ptr->cmana_frac) / p_ptr->mana * new_mana; p_ptr->cmana = value >> 16; p_ptr->cmana_frac = value & 0xFFFF; } else { p_ptr->cmana = new_mana; p_ptr->cmana_frac = 0; } p_ptr->mana = new_mana; /* can't print mana here, may be in store or inventory mode */ #ifdef ATARIST_MWC py.flags.status |= (holder = PY_MANA); #else py.flags.status |= PY_MANA; #endif } } else if (p_ptr->mana != 0) { p_ptr->mana = 0; p_ptr->cmana = 0; /* can't print mana here, may be in store or inventory mode */ #ifdef ATARIST_MWC py.flags.status |= (holder = PY_MANA); #else py.flags.status |= PY_MANA; #endif } } /* Increases hit points and level -RAK- */ static void gain_level() { register int32 dif_exp, need_exp; vtype out_val; register struct misc *p_ptr; register class_type *c_ptr; p_ptr = &py.misc; p_ptr->lev++; (void) sprintf(out_val, "Welcome to level %d.", (int)p_ptr->lev); msg_print(out_val); calc_hitpoints(); need_exp = player_exp[p_ptr->lev-1] * p_ptr->expfact / 100; if (p_ptr->exp > need_exp) { /* lose some of the 'extra' exp when gaining several levels at once */ dif_exp = p_ptr->exp - need_exp; p_ptr->exp = need_exp + (dif_exp / 2); } prt_level(); prt_title(); c_ptr = &class[p_ptr->pclass]; if (c_ptr->spell == MAGE) { calc_spells(A_INT); calc_mana(A_INT); } else if (c_ptr->spell == PRIEST) { calc_spells(A_WIS); calc_mana(A_WIS); } } /* Prints experience -RAK- */ void prt_experience() { register struct misc *p_ptr; p_ptr = &py.misc; if (p_ptr->exp > MAX_EXP) p_ptr->exp = MAX_EXP; while ((p_ptr->lev < MAX_PLAYER_LEVEL) && (player_exp[p_ptr->lev-1] * p_ptr->expfact / 100) <= p_ptr->exp) gain_level(); if (p_ptr->exp > p_ptr->max_exp) p_ptr->max_exp = p_ptr->exp; prt_long(p_ptr->exp, 14, STAT_COLUMN+6); } /* Calculate the players hit points */ void calc_hitpoints() { register int hitpoints; register struct misc *p_ptr; register int32 value; #ifdef ATARIST_MWC int32u holder; #endif p_ptr = &py.misc; hitpoints = player_hp[p_ptr->lev-1] + (con_adj() * p_ptr->lev); /* always give at least one point per level + 1 */ if (hitpoints < (p_ptr->lev + 1)) hitpoints = p_ptr->lev + 1; if (py.flags.status & PY_HERO) hitpoints += 10; if (py.flags.status & PY_SHERO) hitpoints += 20; /* mhp can equal zero while character is being created */ if ((hitpoints != p_ptr->mhp) && (p_ptr->mhp != 0)) { /* change current hit points proportionately to change of mhp, divide first to avoid overflow, little loss of accuracy */ value = (((long)p_ptr->chp << 16) + p_ptr->chp_frac) / p_ptr->mhp * hitpoints; p_ptr->chp = value >> 16; p_ptr->chp_frac = value & 0xFFFF; p_ptr->mhp = hitpoints; /* can't print hit points here, may be in store or inventory mode */ #ifdef ATARIST_MWC py.flags.status |= (holder = PY_HP); #else py.flags.status |= PY_HP; #endif } } /* Inserts a string into a string */ void insert_str(object_str, mtc_str, insert) char *object_str, *mtc_str, *insert; { int obj_len; char *bound, *pc; register int i, mtc_len; register char *temp_obj, *temp_mtc; char out_val[80]; mtc_len = strlen(mtc_str); obj_len = strlen(object_str); bound = object_str + obj_len - mtc_len; for (pc = object_str; pc <= bound; pc++) { temp_obj = pc; temp_mtc = mtc_str; for (i = 0; i < mtc_len; i++) if (*temp_obj++ != *temp_mtc++) break; if (i == mtc_len) break; } if (pc <= bound) { #ifdef __TURBOC__ /* Avoid complaint about possible loss of significance. */ (void) strncpy(out_val, object_str, (size_t)(pc-object_str)); #else (void) strncpy(out_val, object_str, (pc-object_str)); #endif /* Turbo C needs int for array index. */ out_val[(int)(pc-object_str)] = '\0'; if (insert) (void) strcat(out_val, insert); (void) strcat(out_val, (char *)(pc+mtc_len)); (void) strcpy(object_str, out_val); } } #if 0 /* this is no longer used anywhere */ /* Inserts a number into a string */ void insert_num(object_str, mtc_str, number, show_sign) char *object_str; register char *mtc_str; int number; int show_sign; { int mlen; vtype str1, str2; register char *string, *tmp_str; int flag; flag = 1; mlen = strlen(mtc_str); tmp_str = object_str; do { string = index(tmp_str, mtc_str[0]); if (string == CNIL) flag = 0; else { flag = strncmp(string, mtc_str, mlen); if (flag) tmp_str = string+1; } } while (flag); if (string) { #ifdef __TURBOC__ /* Avoid complaint about possible loss of significance. */ (void) strncpy(str1, object_str, (size_t)(string - object_str)); #else (void) strncpy(str1, object_str, string - object_str); #endif /* Turbo C needs int for array index. */ str1[(int)(string - object_str)] = '\0'; (void) strcpy(str2, string + mlen); if ((number >= 0) && (show_sign)) (void) sprintf(object_str, "%s+%d%s", str1, number, str2); else (void) sprintf(object_str, "%s%d%s", str1, number, str2); } } #endif void insert_lnum(object_str, mtc_str, number, show_sign) char *object_str; register char *mtc_str; int32 number; int show_sign; { int mlen; vtype str1, str2; register char *string, *tmp_str; int flag; flag = 1; mlen = strlen(mtc_str); tmp_str = object_str; do { string = index(tmp_str, mtc_str[0]); if (string == 0) flag = 0; else { flag = strncmp(string, mtc_str, mlen); if (flag) tmp_str = string+1; } } while (flag); if (string) { (void) strncpy(str1, object_str, string - object_str); str1[string - object_str] = '\0'; (void) strcpy(str2, string + mlen); if ((number >= 0) && (show_sign)) (void) sprintf(object_str, "%s+%ld%s", str1, number, str2); else (void) sprintf(object_str, "%s%ld%s", str1, number, str2); } } /* lets anyone enter wizard mode after a disclaimer... - JEW - */ int enter_wiz_mode() { register int answer; if (!noscore) { msg_print("Wizard mode is for debugging and experimenting."); answer = get_check( "The game will not be scored if you enter wizard mode. Are you sure?"); } if (noscore || answer) { noscore |= 0x2; wizard = TRUE; return(TRUE); } return(FALSE); } /* Weapon weight VS strength and dexterity -RAK- */ int attack_blows(weight, wtohit) int weight; int *wtohit; { register int adj_weight; register int str_index, dex_index, s, d; s = py.stats.use_stat[A_STR]; d = py.stats.use_stat[A_DEX]; if (s * 15 < weight) { *wtohit = s * 15 - weight; return 1; } else { *wtohit = 0; if (d < 10) dex_index = 0; else if (d < 19) dex_index = 1; else if (d < 68) dex_index = 2; else if (d < 108) dex_index = 3; else if (d < 118) dex_index = 4; else dex_index = 5; adj_weight = (s * 10 / weight); if (adj_weight < 2) str_index = 0; else if (adj_weight < 3) str_index = 1; else if (adj_weight < 4) str_index = 2; else if (adj_weight < 5) str_index = 3; else if (adj_weight < 7) str_index = 4; else if (adj_weight < 9) str_index = 5; else str_index = 6; return (int)blows_table[str_index][dex_index]; } } /* Special damage due to magical abilities of object -RAK- */ int tot_dam(i_ptr, tdam, monster) register inven_type *i_ptr; register int tdam; int monster; { register creature_type *m_ptr; register recall_type *r_ptr; #ifdef ATARIST_MWC int32u holder; #endif #ifdef ATARIST_MWC if ((i_ptr->flags & (holder = TR_EGO_WEAPON)) && #else if ((i_ptr->flags & TR_EGO_WEAPON) && #endif (((i_ptr->tval >= TV_SLING_AMMO) && (i_ptr->tval <= TV_ARROW)) || ((i_ptr->tval >= TV_HAFTED) && (i_ptr->tval <= TV_SWORD)) || (i_ptr->tval == TV_FLASK))) { m_ptr = &c_list[monster]; r_ptr = &c_recall[monster]; /* Slay Dragon */ if ((m_ptr->cdefense & CD_DRAGON) && (i_ptr->flags & TR_SLAY_DRAGON)) { tdam = tdam * 4; r_ptr->r_cdefense |= CD_DRAGON; } /* Slay Undead */ #ifdef ATARIST_MWC else if ((m_ptr->cdefense & CD_UNDEAD) && (i_ptr->flags & (holder = TR_SLAY_UNDEAD))) #else else if ((m_ptr->cdefense & CD_UNDEAD) && (i_ptr->flags & TR_SLAY_UNDEAD)) #endif { tdam = tdam * 3; r_ptr->r_cdefense |= CD_UNDEAD; } /* Slay Animal */ else if ((m_ptr->cdefense & CD_ANIMAL) && (i_ptr->flags & TR_SLAY_ANIMAL)) { tdam = tdam * 2; r_ptr->r_cdefense |= CD_ANIMAL; } /* Slay Evil */ else if ((m_ptr->cdefense & CD_EVIL) && (i_ptr->flags & TR_SLAY_EVIL)) { tdam = tdam * 2; r_ptr->r_cdefense |= CD_EVIL; } /* Frost */ #ifdef ATARIST_MWC else if ((m_ptr->cdefense & CD_FROST) && (i_ptr->flags & (holder = TR_FROST_BRAND))) #else else if ((m_ptr->cdefense & CD_FROST) && (i_ptr->flags & TR_FROST_BRAND)) #endif { tdam = tdam * 3 / 2; r_ptr->r_cdefense |= CD_FROST; } /* Fire */ #ifdef ATARIST_MWC else if ((m_ptr->cdefense & CD_FIRE) && (i_ptr->flags & (holder = TR_FLAME_TONGUE))) #else else if ((m_ptr->cdefense & CD_FIRE) && (i_ptr->flags & TR_FLAME_TONGUE)) #endif { tdam = tdam * 3 / 2; r_ptr->r_cdefense |= CD_FIRE; } } return(tdam); } /* Critical hits, Nasty way to die. -RAK- */ int critical_blow(weight, plus, dam, attack_type) register int weight, plus, dam; int attack_type; { register int critical; critical = dam; /* Weight of weapon, plusses to hit, and character level all */ /* contribute to the chance of a critical */ if (randint(5000) <= (int)(weight + 5 * plus + (class_level_adj[py.misc.pclass][attack_type] * py.misc.lev))) { weight += randint(650); if (weight < 400) { critical = 2*dam + 5; msg_print("It was a good hit! (x2 damage)"); } else if (weight < 700) { critical = 3*dam + 10; msg_print("It was an excellent hit! (x3 damage)"); } else if (weight < 900) { critical = 4*dam + 15; msg_print("It was a superb hit! (x4 damage)"); } else { critical = 5*dam + 20; msg_print("It was a *GREAT* hit! (x5 damage)"); } } return(critical); } /* Given direction "dir", returns new row, column location -RAK- */ int mmove(dir, y, x) int dir; register int *y, *x; { register int new_row, new_col; int bool; switch(dir) { case 1: new_row = *y + 1; new_col = *x - 1; break; case 2: new_row = *y + 1; new_col = *x; break; case 3: new_row = *y + 1; new_col = *x + 1; break; case 4: new_row = *y; new_col = *x - 1; break; case 5: new_row = *y; new_col = *x; break; case 6: new_row = *y; new_col = *x + 1; break; case 7: new_row = *y - 1; new_col = *x - 1; break; case 8: new_row = *y - 1; new_col = *x; break; case 9: new_row = *y - 1; new_col = *x + 1; break; } bool = FALSE; if ((new_row >= 0) && (new_row < cur_height) && (new_col >= 0) && (new_col < cur_width)) { *y = new_row; *x = new_col; bool = TRUE; } return(bool); } /* Saving throws for player character. -RAK- */ int player_saves() { /* MPW C couldn't handle the expression, so split it into two parts */ int16 temp = class_level_adj[py.misc.pclass][CLA_SAVE]; if (randint(100) <= (py.misc.save + stat_adj(A_WIS) + (temp * py.misc.lev / 3))) return(TRUE); else return(FALSE); } /* Finds range of item in inventory list -RAK- */ int find_range(item1, item2, j, k) int item1, item2; register int *j, *k; { register int i; register inven_type *i_ptr; int flag; i = 0; *j = -1; *k = -1; flag = FALSE; i_ptr = &inventory[0]; while (i < inven_ctr) { if (!flag) { if ((i_ptr->tval == item1) || (i_ptr->tval == item2)) { flag = TRUE; *j = i; } } else { if ((i_ptr->tval != item1) && (i_ptr->tval != item2)) { *k = i - 1; break; } } i++; i_ptr++; } if (flag && (*k == -1)) *k = inven_ctr - 1; return(flag); } /* Teleport the player to a new location -RAK- */ void teleport(dis) int dis; { register int y, x, i, j; do { y = randint(cur_height) - 1; x = randint(cur_width) - 1; while (distance(y, x, char_row, char_col) > dis) { y += ((char_row-y)/2); x += ((char_col-x)/2); } } while ((cave[y][x].fval >= MIN_CLOSED_SPACE) || (cave[y][x].cptr >= 2)); move_rec(char_row, char_col, y, x); for (i = char_row-1; i <= char_row+1; i++) for (j = char_col-1; j <= char_col+1; j++) { cave[i][j].tl = FALSE; lite_spot(i, j); } lite_spot(char_row, char_col); char_row = y; char_col = x; check_view(); creatures(FALSE); teleport_flag = FALSE; } moria-5.6.debian.1/README0000644000175000017500000000554311074760100013046 0ustar pjbpjb Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria, in the files/COPYING file. If not, see . This is the source for Umoria 5.6, a dungeon exploration game. This is based on James Wilson's second major release of the game. These sources have been compiled successfully at least once in the following environments: UNIX (4.2 BSD, 4.3 BSD, SYS V, Xenix, HP-UX, and many similar systems), IBM-PC (MSC 5.0, Turbo C 2.0), Mac (MPW 3.0, Think C 4.0), Atari ST (MWC, GCC, TC 2.0), Amiga (Aztec C 5.0), and VMS. The following ports have been added but not tested other than by the people who sent them: 386BSD, HP Apollo, Linux, Lattice C. I consider these to be production sources. They should work without trouble on all of the systems mentioned above. Some minor bugs must surely remain, but there should be no major program bugs encountered. People who are accustomed to Umoria 4.87 MUST read the file doc/FEATURES.NEW which documents many of the user visible features. Don't send me bug reports unless you have read the file. Umoria 5.x does not understand Umoria 4.87 savefiles. The changes to the game are so great, that supporting the old savefile format is not worth the effort. Implementing a savefile conversion program will be an almost impossible task, and at least two people have tried and not succeeded. You may distribute modified copies of this game. However, you must clearly indicate the extent and purpose of the changes. Also, if the changes are extensive, I request that you call your sources something other than `umoria' so that they won't be confused with my version of the game. I would also appreciate receiving a copy of your changes, so that good ideas can be added back into my version. David Grabiner Internet electronic mail addess: grabiner@alumni.princeton.edu Jim Wilson 856 University Ave. Palo Alto, CA 94301 USA internet electronic mail address: wilson@kithrup.com If the above addresses fail, then try contacting the alumni organizations of Princeton University for David Grabiner, or Case Western Reserve Univ (Cleveland, OH) or Univ California at Berkeley for Jim Wilson, for current addresses. These addresses are expected to remain valid for an unknown length of time. First revision (alpha): February 28, 1990 Second revision (beta): May 4, 1990 Third revision (production): March 25, 1991 moria-5.6.debian.1/ChangeLog.91-940000644000175000017500000005322505613625276014442 0ustar pjbpjb::::::: 1991 :::::::: ---------- 1/4 spells.c: light_area(), always light area immediately next to player even if in a room, could be standing on the edge of a room monsters.c: Grave Wight, no longer has confusion spell, no other wight/wraith has it misc2.c: get_spell(), when enter invalid character, print "You don't know that prayer." instead of "spell" for priests/etc. creature.c: make_attack(), creatures which are repelled should not be confused because they did not hit the player death.c: exit_game(), delete #ifndef TURBOC around the restore_term() call io.c: restore_term(), delete the call to clear() in the MSDOS code, it was trying to use curses after curses had been exited ---------- 1/22 files.c: call pause_line(23) after printing hours file constant.h, config.h: constant.h should always be included before config.h, because some systems redefine constants in config.h rnd.c: include config.h after constant.h main.c, misc2.c, save.c, signals.c: include constants.h before config.h misc2.c, vms/getch.c: new function user_name() for VMS, fix get_name() in misc2.c to call it ------- 1/30 moria2.c: hit_trap(), add msg_print(CNIL) for the trap door case -------- 2/4 io.c: for ATARIST_MWC, use 240 instead of '#' for walls save.c: for ATARIST_MWC, convert 240 to '#' when saving, and '#' to 240 when loading, to avoid conversion problems --------- 2/8 create.c: monval(), cast i to int, otherwise some compilers do the arithmetic with unsigned characters --------- 2/19 makefile: add new macro CURSES, define it for BSD/SYS V/and Xenix config.h: add config info for XENIX, define SYS_V and unix, only undefine register for MSC versions less than 600 (6.00?) creature.c: mon_move, comment out register decl for r_ptr for XENIX systems to avoid a compiler bug misc2.c: place_gold, comment out register decl for t_ptr for XENIX systems to avoid a compiler bug unix.c: ifdef out include of termio.h, for XENIX add include of sys/types.h and define bzero as memset, test for unix or M_XENIX at the top Makefile: add optional commands to install target which chown/chgrp everythin to bin, and put pointer to it at the top ---------- 2/25 util/score: Two new utilities, prscore to print scorefiles, and delscore to delete one entry from a scorefile. config.h: add MORIA_* macros for the Atari ST with GCC death.c, externs.h, io.c, main.c, signals.c, variable.c: Apply Atari ST/GCC patches from Scott Kolodzieski. -------- 3/1 death.c: Amiga must open/close scorefile like MSDOS&VMS io.c: init_curses(),restore_term(), fix bugs in AMIGA code, add code to release resources amiga/*: updated versions of amiga source files, from cg37717@lion.eng.clemson.edu, Corey Gehman atari_st/curscomp: complete rewrite of the curses code by Hildo Biersma store2.c: get_haggle(), do not accept an increment value of zero, turn off increment flag instead of accepting it -------- 3/2 store2.c: store_purchase(), store_prt_gold call was inside `if' now after, did not update gold if store had 13 items and you bought the 13th -------- 3/11 moria1.c: sub3_move_light(), don't print over old location if find_flag is true, unless find_prself is also true, this speeds up movement in find mode by eliminating unnecessary drawing of characters moria2.c: hit_trap(), call move_light() for the teleport trap case, to light up the trap misc1.c, save.c, treasure.c: change ATARIST_MWC ifdefs for using graphic character to ATARI_ST which is true for both MWC and TC io.c: remove all ATARIST_MWC diffs which were needed for the old non-standard curses, change the rest to be ATARI_ST, since both MWC and TC need them -------- 3/14 source/*: add Mac THINK C support mac/dumpres/*: add Mac THINK C support mac/scrnmgr/*: add Mac Think C support moria1.c: find_init(), when !light_flag and !find_prself, must erase the player's '@', because sub3_move_light() won't, see 3/11 change above ------- 3/15 mac/*: add Mac THINK C support *: put file name and 1991 copyrights in all source files ------- 3/23 save.c: prevent resurrection of a total winner character constants.h, creature.c, monsters.c, recall.c: add new flag CM_ONLY_MAGIC, set this flag in creature.c, check the flag in recall.c, allows recall to print movement speed for Quylthulgs creature.c: when a wand is drained of charges, inscribe it as {empty} if it is not known2 -------- 3/24 files.c, ibmpc/ms_misc.c: ifdefed out msdos_intro(), since that routine is obsolete now doc/moria.6: add -S option to list at the top ibmpc/CONFIG.DOC: update for Umoria 5.x, remove kneller's address, and put in my address ------- 3/25 config.h, constant.h, */*.c: move VMS definition for ESCAPE from config.h to constant.h, now all files include config.h before constant.h *: linted all sources files, changed version numbers to 5.3 ------- 3/30 vms/*, ibmpc/ms_misc.c, config.h, death.c, dungeon.c, externs.h, files.c, io.c, save.c: merge in changes from Ralph Waters, which are needed to compile the sources under VMS and IBM-PC/Turbo C. moria2.c, store2.c, *.c: get_item(), show_inven() take new parameter mask, if mask is non-zero, they only list items indicated by mask array, store_sell() calculates a mask based on what store will buy store2.c: purchase_haggle(), sell_haggle(), if the auto increment is larger than the difference between the store's offer and the player's offer, then set the auto increment to the exact difference dungeon.c, externs.h, moria1.c, moria2.c, variable.c: eliminate search_flag, it was redundant, replace all uses with (py.flags.status & PY_SEARCH) tables.c: remove good armor items from armory, to force players to search for them in the dungeons, hard leather boots, iron helm, partial plate, full plate misc1.c: alloc_monster(), always create dragons sleeping here, to give the player a sporting chance moria1.c: inven_command(), when pack not empty and show_weights flag true, display capacity along with weigth carried on first line of inventory spells.c: build_wall(), permanently light walls created within range of player's lamp spells.c: earthquake(), fix it to act just like build_wall when a monster is trapped in a wall creature.c, externs.h: movement_rate(), now static *: release 5.3.1 sources ------- 4/27 ms_misc.c, externs.h: change declarations of warn() to match definition, change declaration and definition of error() to match warn(), externs.h: fix declarations for sleep(), find_init(), show_inven(), get_item() death.c: display_scores(), don't set player_uid for non UNIX/VMS system duplicate_character(), ifdef out code which is unreachable for non UNIX/VMS system, make all returns have a value sets.c: set_null(), add a #pragma argused for TURBO C ms_misc.c: fix three lines that had an assignment inside an if externs.h: add prototypes/declarations for VMS files getch.c and uexit.c moria1.c: see_wall(), change ATARIST_MWC ifdef to ATARI_ST atari_st/curscomp/curses.c: winsch(), first loop ran in wrong direction externs.h: add declarations for atari st functions atari_st/moria.prj: new file, TC project file for Umoria death.c: highscores (), change fseed to fseek, typing error creature.c, death.c, desc.c, dungeon.c, files.c, io.c, moria1.c, moria2.c, store2.c, wizard.c, atarist.c: include stdlib.h if ATARIST_TC to get prototypes for standard library functions generate.c: for ATARIST_TC, include atarist/curscomp/curses.h: change mvadd* macros from compound statements to conditional expressions, so that all returns values are error checked io.c: for ATARIST_TC, include ext.h to properly define (?) sleep config.h: for ATARIST_TC, define index strchr save.c: sv_write()/get_char(), define t_ptr for both MSDOS and ATARI_ST; get_char(), change ATARIST_MWC ifdef around chmod call to ATARI_ST include time.h for ATARIST_TC unix/Makefile: change ONWER to OWNER creature.c: creatures(), give moves to monsters trapped in rock, so that they will die/dig out immediately, mon_move() if a monster in rock is already dead, don't kill it again *: update address info in all files io.c: change __GNU_C_ to __GNUC__ config.h: the test for undefining 'register' was wrong, it was undefing it for all non-MSC compilers moria2.c: tunnel(), heavy weapon code wrong, eliminate >>2 of penalty, add penalty instead of subtracting it help.c: ident_char(), add period after Giant Frog. monsters.c: novice priest, change sleep from 10 to 5 to match other novice 'p' moria1.c, store2.c, *.c: get_item() new parameter 'message', when invalid letter hit, print this message if non-zero instead of beeping, store_sell() pass message "I do not buy such items.", fix all other callers to pass CNIL -------- 4/28 misc2.c, files.c: put_misc2(), file_character(), when player at max level, don't print a number for Exp to Adv, instead print ****** io.c: msg_print(), put multiple messages on the same line if they are short enough ------- 5/22 externs.h: ifdef out declaration of sprintf for NeXT io.c (init_curses): correct atarist/GNUC code for signal call, ifdef was wrong ------- 7/6 spells.c (unlight_area): Unlight all floor spaces with `lr' set, instead of just the room floors spaces. This darkens the doorways. moria1.c (light_room): Add code to set the fm flag, necessary so that the above fix does not unlight doors that it shouldn't. io.c (msg_print): Don't combine NULL messages with other messages. save.c (get_char): Use msg_print when printing the `departed spirit' message. -------- 7/26 store2.c (purchase_haggle, sell_haggle): If the automatic increment plus the last offer passes the shop keepers current ask, then clear the incr. -------- 10/5 *: Add changes needed to prevent warnings from the IBM-PC TURBO C compiler. misc[1234].c, moria[1234].c: misc[12].c and moria[12].c were each split into two files, because they were too large for TURBO C's integrated environment *: adjust all makefiles, externs.h, etc to account for new moria/misc files TCCONFIG.TCU, TCPICK.TCU: new files, uuencoded copies of Turbo C setup files config.h, ms_misc.c: New define USING_TCIO, used to prevent including curses.h in ms_misc.c. Defaults to defined if using TURBOC on an IBM-PC. io.c: delete special purpose AMIGA code, it now uses curses amiga/amiga.h: Deleted. amiga/amiga.c: Delete all curses stubs. -------- 10/6 macrsrc.h: change type of resType, ResID to long macrsrc.c: eliminated search_flag from macrsrc.c (see 3/30 changes) config.h: put back switches RSRC, RSRC_PART1 and RSRC_PART2 ScrnMgr.ro: changed def of MBAR #228 (fixes crash on Mac Plus) and INFO #1 (Make default window be full screen) ScrnMgr.c: check for reconfig flag enabled for THINK_C, add recognition of MacClassic (and LC?) keyboard, now assumes unknown keyboard type has control key, other misc cleanups moria.ro: changes version string macconf.c: config.h included for consistency mac.c: added support for 8-column tabs mac/Install.doc: new file, installation instructions for THINK C macconf.c, machelp.c, macscore.c scrnmgr.c: covered up error in THINK C includes files OK/Cancel for ok/cancel death.c, save.c: delete setmode calls for IBM-PC, instead open files in binary mode --------- 10/12 *: Changed version number to 5.4. save.c: change code to accept savefiles with version numbers greater than the version number of the game, savefile format frozen as of 5.2.2 externs.h: ifdef out the troublesome sprintf declaration config.h: force `unix' to be defined for unix systems, since some stupid systems (e.g. AIX) don't already define it --------- 10/15 externs.h, moria4.c, ms_misc.c: correct typos discovered under MSDOS --------- 10/19 spells.doc, exp.doc: New documentation files. --------- 10/26 vms/uexit.c, externs.h, io.c, signals.c: Define uexit as void, and ifdef out exit declarations when VMS. vms/moria.opt: add misc[34].obj and moria[34].obj ibmpc/ms_misc.c: correct typo in error() pr_items.c, pr_monst.c: main now returns 0 CONFIG.DOC, TERMCAP, ms_ansi.c: use le/do instead of obsolete bc/xd dragon.inf: moved from util/weapons to doc, and updated it to be accurate spoilers: Update from USENET FAQ posting. --------- 11/17 io.c: ifdef out code checking for 8 char TABS, because it assumes that the screen is exactly 80 characters wide moria[12].[ms/txt]: Correct a few typos. *: Fix all file permissions. ::::::: 1992 :::::::: Maintenance taken over by David Grabiner --------- 7/16 moria4.c: bash(), use random direction if player is confused spells.c: fire_ball(), fire_bolt(), don't update recall if monster not lit; this can happen if bolt hits an invisible monster spells.c: speed_monsters(), sleep_monsters2(), dispel_creature(), turn_undead(), only affect creatures within MAX_SIGHT spells.c: mass_poly(), area of effect should be <= MAX_SIGHT, was < spells.c: destroy_area(), remove light from player's spot spells.c: enchant(), add new variable limit, chance of failure is now (plusses/limit), with very slight chance of success over limit scrolls.c: when enchanting melee weapons to damage, set limit to weapon's maximum damage, otherwise use 10 to give behavior similar to old method misc2.c: magic_treasure(), make standard deviation of damage bonus on a melee weapon proportional to weapon's maximum damage; these changes mean that daggers can no longer become powerful weapons treasure.c: the Zweihander has now become a great weapon, value increased from 1000 to 1500 externs.h: fix declaration for enchant() staffs.c, wands.c: give everyone a slight chance to use difficult wands and staffs, otherwise a warrior will never be able to use many items --------- 7/23 death.c: print_tomb(), insert msg_print(CNIL) so that "You are using:" and "You are carrying:" don't get combined as one message; this made it impossible to see the equipment list store2.c: haggle_insults(), insert msg_print(CNIL) so that insult is always recognizable store2.c: purchase_haggle() and sell_haggle(), new variable didnt_haggle, don't call updatebargain if no haggle store1.c: noneedtobargain(), changed to sliding scale, (good-3*bad) must be more than 5 + (price/50) to skip haggling, so that haggling for cheap items is over quickly, but can still eventually skip haggle for all items store1.c: updatebargain(), now update for all items worth >9 gold, instead of just 10-999, since it is now possible to skip haggling for more valuable items as well --------- 7/25 moria4.c: bash(), unsuccessful bash takes a turn; otherwise, you can attempt to bash in different directions while confused or to locate invisible monsters; eliminate variable no_bash --------- 7/27 check all above changes moria4.c: bash(), get "You bash at empty space" method when bashing a wall, corrected to "nothing interesting happens"; this also prevents bashing from locating a secret door --------- 8/9 merge in all changes from 5.4.0 to 5.4.1 creature.c: update attack information only if monster is visible; update death information even if monster is not visible, since information will be on tombstone *: change version number to 5.5.0 --------- 8/12 spells.c: enchant(), guard against randint(0) if called with limit of 0 (it shouldn't be). moria4.c: throw_object(), py_bash(), don't do negative damage shortnam.sed, spells.c: fire_ball(), fix spelling of "envelops" doc/faq: remove old spoilers file, and put current FAQ here instead *: put my name (DJG) in credits as contact *: change copyright date in all source files to 1992 ---------- 8/13 release umoria 5.5.0 ---------- 10/26 doc/moria[12].[ms,txt]: correct some typos, and make changes for 5.5.0 ---------- 10/31 misc4.c: scribe_object() allowed inscriptions longer than 12 characters if 13-24 characters availble for inscription, could overwrite other data ::::::: 1994 :::::::: ---------- 6/6 scrolls.c: aggravate monster should give "humming noise" before "stirring" scrolls.c: always identify scrolls which print a message unix/unix.c: change from obsolete getpw() to getpwuid() to get UID death.c: #include seems to be needed on XENIX and SYSV death.c: fix #ifdef (...) || defined(...) save.c: set fd=-1 after closing file to prevent double close dungeon.c: move hero/superhero to first status check so that player's HP won't go below 0 in mid-turn (killing him) and then become positive doc/moria[12].ms: fixes so that file works with groff store1.c: sell_price(), check for consistent sale prices compared pointers rather than values create.c: get_all_stats(), set player level to 1 before calling set_use_stat with constitution (which used level to check hit points) misc3.c: misspelled variable "holderr" in MWC-specific code misc3.c: prt_experience(), put check against max level in while loop so that level gain is never tested if player is max level misc3.c: gain_level(), corrected comment for loss of extra experience when player gains multiple levels moria3.c: monster_death(), don't make player a winner if already dead store2.c: get_haggle(), %d should be %ld misc3.c: todis_adj(), case of dexterity 3 was omitted spells.c: wall_to_mud(), may find objects in rubble as with tunneling ---------- 6/7 io.c, signals.c: included changes from Andrew Chernov for 386BSD support io.c, config.h: included changes from Berthold Gunreben for HP-UX support config.h, death.c, files.c: added patches for HP Apollo, which doesn't allow multiple processes to use the same file config.h: defined MORIA_LIB to contain pathname for moria/files, to simplify configuration moria1.c: inven_command(), get_item(), added code from Harry Johnston which allows use of 0-9 to specify an item with the corresponding inscription doc/moria[12].ms: documented above change files/version.hlp: my name appeared both as author and "other contributor" scrolls.c: set AC bonus on cursed weapon, hit/dam bonuses on cursed armor to zero (in case HA/DF/gauntlets of slaying had bonus) creature.c: don't print message when invisible monsters recover from bash creature.c, moria3.c, spells.c: reworked monster confusion, monster's confused value now gives duration, turn_undead has guaranteed duration equal to player's level, other confusion random creature.c: undead which have been turned will flee rather than moving randomly, attack only if cornered recall.c: print "It is resistant to" if monster has not cast any spells but breath flag is known (because monster resisted an attack) monsters.c: allow monsters to resist attacks if they have no breath weapon but use the attack type (so fire giants resist fire) sets.c: new function set_large(), identifies objects too large to fit in a chest or be carried by small creatures misc3.c: get_obj_num(), new parameter must_be_small to generate only small objects when appropriate; place_object() passes it files.c: random object sample passes must_be_small constant.h, treasure.c, monsters.c, moria3.c, recall.c: new constant CM_SMALL_OBJ for chests, and for monsters carrying only small objects, check it in monster_death() by setting a bit in treasure type, allow it to be recalled moria3.c: summon_object(), object must be small if bit flagged above many: change all other calls to place_object to set must_be_small to FALSE externs.h: fix declaration of get_obj_num(), place_object(), add set_large() store1.c: noneedtobargain(), change scale again, (good-3*bad-5) must be positive and its square must be at least price/50, this allows high-level characters to become good bargainers for expensive items ---------- 6/8 lint all above changes, fix assorted typos recall.c: recalled spell frequency for non-spellcasters in wizard mode monsters.c: checked small objects/resistances for consistency, fixed error creature.c: creatures given resistance by setting of breath bits tried to cast spell, calling randint(0) moria3.c: error in testing type caused all monsters which should drop both objects and gold to drop only gold creature.c: turned undead must call get_moves so they know which way to flee ---------- 6/9 moria1.c: inven_command(), get_item(), print 0-9 in prompt message when appropriate moria[12].ms: clarified that digit inscriptions work only on items in pack prayer.c: strengthened Holy Word player.c: reduced failure chance for Holy Word check all changes, fixed more typos ---------- 6/10 moria1.c: inven_command(), get_item(), 0-9 was printed in wrong place ---------- 6/22 spells.c: td_destroy(), td_destroy2(), don't disarm/unlock chests that are already empty treasure.c: up staircase had extra space after name doc/moria[12].ms: proofread, fix many typos ---------- 6/25 monsters.c: allow thieves to pick up objects on the floor main.c,config.h,amiga/amiga.c,amiga/timer.c: included changes from Ronald Cook for Lattice C support on Amiga death.c,io.c,signals.c,unix.c,config.h: included changes from Brian Johnson for Linux support changed version number to 5.5.1 fix more lint errors util/mergemem: code from Eric Bazin to merge monster memories *: changed all copyright dates to 1994 released version 5.5.1 ---------- 7/5 death.c: || !defined(APOLLO) should be && ---------- 7/11 store2.c: get_haggle, changed %ld back to %d since variable is 16 bits ---------- 7/20 treasure.c: fixed many inconsistencies, mostly prices and names misc2.c: magic_treasure(), fixed values of SU and SA, which weren't changed when see invisible was moved from SA to SU; also changed magical bonuses for these weapons store2.c: increase_insults(), don't clear out haggling record if player is thrown out (it might be worse than zero), just penalize as for bad bargain ---------- 7/21 treasure.c: fixed a few more inconsistencies with items files.c, misc32.c: file_character(), put_misc2(), don't print "Exp to Adv" if over max_level (i.e., winner) files.c: file_character(), leave enough space for printing 8-digit experience points misc3.c: put_misc2(), make display consistent with above change misc3.c: new function prt_8lnum(), print a long variable in 8 digits of space, needed by revised put_misc2() above death.c: need flock hack for HPUX io.c: #include for HPUX was inside #if 0 ibmpc/*: fix several typos in PC-specific files, also one in config.h changed version to 5.5.2 released version 5.5.2 moria-5.6.debian.1/misc/0000755000175000017500000000000005613574236013131 5ustar pjbpjbmoria-5.6.debian.1/misc/moria.msg0000644000175000017500000001370705613574236014760 0ustar pjbpjbFrom boyne@hplvla.hp.com Tue Feb 27 08:03:46 1990 Received: from hp-sde.sde.hp.com by ernie.Berkeley.EDU (5.61/1.36) id AA19235; Tue, 27 Feb 90 08:03:44 -0800 Received: from hp-lvld.lvld.hp.com by hp-sde.sde.hp.com with SMTP (15.11.1.3/15.5+IOS 3.13) id AA03131; Tue, 27 Feb 90 08:03:15 pst Received: from hplvla.HP.COM by hplisa.lvld.hp.com; Tue, 27 Feb 90 09:04:05mst Received: from hplvre.HP.COM by hplvla.HP.COM; Tue, 27 Feb 90 09:04:43 mst Received: by hplvre.HP.COM; Tue, 27 Feb 90 09:04:41 mst Date: Tue, 27 Feb 90 09:04:41 mst From: Art Boyne Message-Id: <9002271604.AA19981@hplvre.HP.COM> To: wilson@ernie.Berkeley.EDU Subject: Re: Hmmmmm (actually enchanting plusses) Status: RO > > I have an odd little question to ask... how does one increase the > > first `plus' on a pick or shovel? The two enchantment scrolls (Damage and > > To-Hit) seem to increase the second set of pluses, and have no effect on > > the first. > > This is a possibility. However, it has to be done carefully to avoid > problems. There must be a limit on how high digging ability can be increase > just like weapons/armor are effectively limited to +10. I think +10 is > ridiculously high for digging though, perhaps limiting it to 5 would be OK. Actually, I have found on several occasions Gnomish Shovels (+6), but never anything higher (both in umoria 4.87 and PC-MORIA 4.873). So perhaps +6 should be the asymptotic limit, with decreasing chance of success for each +, similar to enchanting weapon. >Also, if this were allowed, then creatures should be allowed to 'disenchant' >the digging ability of weapons, and there should be traps/scrolls/whatever >that reduce the digging ability. And there are probably some other changes >needed as well that don't come immediately to mind. Certainly - disenchanter creatures could affect digging ability, and (see below) the enchantments on rings, etc. Digging ability could also be reduced by repeatedly digging through "hard" rock - say up to a 1% chance based on what you are digging through. >>You can't. Period. This is another feature I would like to see changed, >>along with being able to increase the enchantment of rings, etc. > >I am very leary about adding this, because rings are permanent magic items. >In particular, letting someone enchant a ring of speed to +2 or higher will >seriously unbalance the game, as this is an incredible advantage for a >player. Again, allowing disenchanter creatures to affect this would overcome the imbalance. Also, there could be a small chance that an enchant item scroll could destroy the item. In fact, this should probably be the case even for the existing enchant weapon/armor scrolls, since right now you have *nothing* to lose by trying 100 times to get an extra + on weapons/armor. Also, I still would like to see a very small chance that enchanting weapons/armor would produce a special weapon (SD/SU/SE/SM/HA/DF) or special armor (RC/RA/RL/RF/R). Again, this would be counterbalanced by the (slightly greater?) chance of destroying the item. Perhaps, too, disenchanter creatures could be allowed to remove the special attributes. Art Boyne, boyne@hplvla.hp.com From ucbvax!decwrl!ames!think!samsung!usc!cs.utexas.edu!tut.cis.ohio-state.ed Status: RO Article 4487 of rec.games.moria: Path: ucbvax!decwrl!ames!think!samsung!usc!cs.utexas.edu!tut.cis.ohio-state.e >From: dtate@unix.cis.pitt.edu (David M Tate) Newsgroups: rec.games.moria Subject: Re: Enhancements to Umoria5.0 : the One Ring Keywords: One Ring Message-ID: <22578@unix.cis.pitt.edu> Date: 27 Feb 90 16:46:31 GMT References: <1990Feb22.005217.22427@cs.rochester.edu> <562@auvax.AthabascaU.CA Reply-To: dtate@unix.cis.pitt.edu (David M Tate) Distribution: all Organization: Univ. of Pittsburgh, Comp & Info Services Lines: 47 In article <562@auvax.AthabascaU.CA> kevinc@cs.AthabascaU.CA (Kevin Crocker) > >Remember, at least some of the Elven rings still existed, the Dwarven >rings are presumably lost in the Mines of Moria, HINT!, HINT!, and of >course the Nine walk abroad but are but wraiths of doom. > >All kinds of interesting thoughts appear. > Actually, if I remember my Ring-lore correctly, the seven were all taken by Sauron. The last was the ring of Thrain, which was taken from Thror (or was it Thrain?) by Sauron in the dungeons of Dol Guldor. No more Rings of Power floating around in Moria. The only rings still "available" are the three rings (Narya, Nenya, Vilya) of the Elves, made by Celebrimbor. But I'm getting pedantic... I, too, would love to see an even-more-Tolkienish descendant of Moria...if you get tired of Moria, maybe you could bash your way across Mirkwood to deal with Smaug or the Necromancer. Having Nazgul would add some spice, too. And for artifacts, you could find a palantir, which would let you look at any desired portion of the level as if you were in the room(s), but from a distance. Of course, I'm sure Jim Wilson is reading these postings and saying "Yeah, in your dreams." :-) I do like the idea of having more "special attribute" items, good and bad. You could actually make the choices a lot harder by mixing them up: what would *you* do if you found Boots [3,+7] (R) of Noise? Or ego weapons with both good and bad side effects (remember "Bessman's Flailing Hammer", in Larn?). Items of invisibility would be great, too. Any chance of getting Alter-ego Weapons? A dagger (-2,-4) of Summon Undead? Or something that *increases* susceptibility to certain breath/trap attacks, like a ring (or armor) of Susceptibility to Cold/Fire/Poison/Acid/Lightning? How about being able to buy lightning rods in the general store? Plant one in the floor, and all lightning attacks (dragon, wand, whatever) get drawn to it. Just don't stand too close! etc. -- David M. Tate | "It made the basses of their being throb in dtate@unix.cis.pitt.edu | witching chords, and their thin blood pulse | pizzicati of Hosanna..." "A Man for all Seasonings" | -- Wallace Stevens moria-5.6.debian.1/misc/haggle.sug0000644000175000017500000000620605613574236015104 0ustar pjbpjbFrom ghudson@cie.uoregon.edu Tue Mar 6 17:09:23 1990 Received: from oregon.uoregon.edu by ernie.Berkeley.EDU (5.61/1.36) id AA19401; Tue, 6 Mar 90 17:09:11 -0800 Received: from cie.uoregon.edu by oregon.uoregon.edu; Tue, 6 Mar 90 17:07 PST Received: by cie.uoregon.edu (MC 2.0/SMI-4.0.1.2(JQJ)) id AA09277; Tue, 6 Mar 90 17:07:48 PST Date: Tue, 6 Mar 90 17:07:48 PST From: ghudson@cie.uoregon.edu Subject: Re: Haggling To: wilson@ernie.Berkeley.EDU Message-Id: <9003070107.AA09277@cie.uoregon.edu> X-Envelope-To: wilson@ernie.Berkeley.EDU Status: RO > Drat. This will ahve to be fixed somehow, maybe by setting a bit in each > individual object when bought/sold, so that it can only contribute to the > good/bad bargain counts once. Reasonable. Shouldn't take too much coding. Since this is getting so complex, you might try to put in some clue as to how good of a bargainer you are, e.g. when you start bargaining, you have a small (10%-20%) chance of getting a message like: The merchant looks at you distatesfully The merchant eyes you with a hint of respect Something like that. Now, on to our (3*bad + 20) formula: Simplified, this could be algorythm'd like so: ptr = 20; case pointer += 3; case pointer -= 1; if (ptr == 0) Okay, that was of course a mishhash of something slightly resembling C code, but you get the idea. But I don't like how if you missed the final offer by one gold piece, your pointer goes up by three, even if the item was worth some 900 to start with. I'd think it'd be better if that was more like: case pointer += (price paid - low price) / low price * 10 So you lose one point for each 10% over the final value that you paid. This isn't particularly accurate, unfortunately, but that might be remedied by a (float) ptr. (I just realized that "ptr" is a pretty dumb name for what should be called "counter" or something. Sorry...) Back to our spoiler solution, do note that one could still buy a bunch of junk and still up (down, via my algorythm) your counter, even though you didn't need the item. I really don't have a solution, other than expanding the code so that each price range (increments of about a hundred, so the first few would be 10-100, 11-200, 201-300 and the last few would be 801-900 and 901-1000 or 901-999, however you work it) gets a separate counter. Natur- ally, this would have to be accompanied by a decrease of the original counter value to 10 or 5 or so (or a different value for each range, since players will buy a lot more items in the 10-100 range). > Thanks for the warning. Just came to my mind. It isn't quite so bad, since items under 10 gp final price don't count, so one couldn't up your counter by buying flasks of oil or something. Greg Hudson ghudson@cie.uoregon.edu "Though the Earth, and all inferior Creatures be common to all Men, yet every Man has a Property in his own Person. This no Body has any Right to but himself." -- John Locke, _Two Treatises of Government_, 2nd Treatise I am blatantly close-minded and refuse to admit it. There are missionaries aplenty, but few enlightened. Believe me. moria-5.6.debian.1/misc/wex.msg0000644000175000017500000002464605613574236014460 0ustar pjbpjbFrom @MCC.COM:wex@MCC.COM Tue Sep 29 07:05:44 1987 Received: from MCC.COM by ji.Berkeley.EDU (5.58/1.25) id AA07225; Tue, 29 Sep 87 07:05:40 PDT Received: from milano.SW.MCC.COM by MCC.COM with TCP; Tue 29 Sep 87 09:06:24-CDT Received: from banzai-inst by milano.SW.MCC.COM (5.52/STP1.51) id AA19878; Tue, 29 Sep 87 09:05:12 CDT Date: Tue, 29 Sep 87 09:04:58 CDT From: Buckaroo Banzai Message-Id: <8709291404.AA11679@banzai-inst.SW.MCC.COM> Received: by banzai-inst.SW.MCC.COM (3.2/STP1.14) id AA11679; Tue, 29 Sep 87 09:04:58 CDT To: wilson@ji.Berkeley.EDU In-Reply-To: James E. Wilson's message of Mon, 28 Sep 87 20:11:15 PDT <8709290311.AA03868@ji.Berkeley.EDU> Subject: UNIX Moria Status: RO No, I haven't looked at your sources yet. There are some serious bugs in the original, which I hope you caught (naturally, I didn't keep a list of them :-( ). I, too, corrected the zillions of spelling mistakes. Mine doesn't pass lint or run on SYS V. I haven't decided how to deal with the rogue-ists who want to use h,j,k,l, etc. I do have a help program and an extended help library. I've also made some changes to make the game better. EG: - you can now recover items from thieving monsters. - when monsters drop treasures, they are dropped where the player can recover them, instead of inside walls. - priests' spells are a little better - they now have Word-Of-Recall as a high-level spell. - breath weapons, fireballs, etc. now affect everyone in the blast radius, including the player and monsters. - monsters are now a little smarter about which spells they use (eg no fireballs from range 1; no teleport-to-me spells from range 1). - a number of useful hints/noises have been added (eg. a multiplying monster now goes 'POP'; some potions have helpful messages - not giveaways; just enough so that they don't all appear to be no-ops). - there are error traps and messages (eg lots of places where there was no 'default' case on a switch) so that the game doesn't do funny things. - the shops' inventories have been fixed up so that more and more- useful items are available (shop inventories can now be multiple pages instead of just two). - there's a Yes/No prompt for accepting a character or re-rolling. - the save file is expanded so that the monster list is kept; as it was, you could escape a monster by saving and restoring. - there was a bug whereby if you were carrying 10 +2,+2 arrows and picked up 10 +0,+0 arrows you'd end up with 20 +2,+2 arrows. That's fixed. There was a bug whereby if you ever got too many treasures on a level, the game could go into an infinite loop. There are others, but I can't remember them off the top. I assume the moria files are on ji.berkeley.edu? What directory? --Alan From @MCC.COM:wex@MCC.COM Tue Sep 29 12:12:25 1987 Received: from MCC.COM by ji.Berkeley.EDU (5.58/1.25) id AA10246; Tue, 29 Sep 87 12:12:21 PDT Received: from milano.SW.MCC.COM by MCC.COM with TCP; Tue 29 Sep 87 14:12:48-CDT Received: from banzai-inst by milano.SW.MCC.COM (5.52/STP1.51) id AA22469; Tue, 29 Sep 87 14:08:46 CDT Date: Tue, 29 Sep 87 14:08:33 CDT From: Buckaroo Banzai Message-Id: <8709291908.AA12132@banzai-inst.SW.MCC.COM> Received: by banzai-inst.SW.MCC.COM (3.2/STP1.14) id AA12132; Tue, 29 Sep 87 14:08:33 CDT To: wilson@ji.Berkeley.EDU In-Reply-To: James E. Wilson's message of Tue, 29 Sep 87 11:11:15 PDT <8709291811.AA09240@ji.Berkeley.EDU> Subject: UNIX Moria Status: RO In some ways, I've made the game "easier," but I think it's more balanced. EG: there's zillions of monsters that drain ST, DX, CO, so I made elven waybread restore those things. I also found that priest had a huge advantage with Sense Invisible, so I made a Ring of See Invisible available in the Mages' shop. (Of course, it's still random, so it doesn't appear most of the time, but there's a chance.) There are a couple of other minor tweaks like that. The reroll-character option was the first request I got from my playtesters. I sort of agree - some days I want to play a mage and it's stupid for me to have to quit lots of games. Another *major* change: I've improved the scoring algorithm. It used to count just gold and exp. Now I add in a bunch of other things. The total score is higher, and the overall effect is to reward smart play (eg if you've spent all your gold to improve your weapon to +4,+4 I now recognize and reward that as if you still had the gold). We should get together and merge our ideas if possible, no? --Alan From @MCC.COM:wex@MCC.COM Wed Sep 30 09:02:55 1987 Received: from MCC.COM by ji.Berkeley.EDU (5.58/1.25) id AA21194; Wed, 30 Sep 87 09:02:52 PDT Received: from milano.SW.MCC.COM by MCC.COM with TCP; Wed 30 Sep 87 11:02:14-CDT Received: from banzai-inst by milano.SW.MCC.COM (5.52/STP1.51) id AA12165; Wed, 30 Sep 87 11:02:08 CDT Date: Wed, 30 Sep 87 11:01:54 CDT From: Buckaroo Banzai Message-Id: <8709301601.AA14128@banzai-inst.SW.MCC.COM> Received: by banzai-inst.SW.MCC.COM (3.2/STP1.14) id AA14128; Wed, 30 Sep 87 11:01:54 CDT To: wilson@ji.Berkeley.EDU In-Reply-To: James E. Wilson's message of Tue, 29 Sep 87 14:05:51 PDT <8709292105.AA11513@ji.Berkeley.EDU> Subject: UNIX Moria Status: RO Got the files transferred and compiled. You haven't reorganized them, I see. I got bloody tired of trying to figure out which routines were in what file (main, moria1, moria2, misc1, misc2?? - BLEAH) and restructured the code into more logical modules. The sizes even out better, too. You also seem to have the problem that's been plaguing me - monsters aren't always visible when they ought to be, especially in dark rooms and corridors. I think there's something wrong in draw_block(). Drat! I was hoping you'd solved that one. Can I transfer you a copy of my code so you can see what I've done? I can also ship you the help files and program that runs on them. Also, how do I get into wizard mode on your moria? ^p doesn't seem to do it, as it does on mine. --Alan From @MCC.COM:wex@MCC.COM Wed Sep 30 15:19:08 1987 Received: from MCC.COM by ji.Berkeley.EDU (5.58/1.25) id AA25694; Wed, 30 Sep 87 15:19:04 PDT Received: from milano.SW.MCC.COM by MCC.COM with TCP; Wed 30 Sep 87 17:18:31-CDT Received: from banzai-inst by milano.SW.MCC.COM (5.52/STP1.51) id AA20759; Wed, 30 Sep 87 17:18:27 CDT Date: Wed, 30 Sep 87 17:18:12 CDT From: Buckaroo Banzai Message-Id: <8709302218.AA16205@banzai-inst.SW.MCC.COM> Received: by banzai-inst.SW.MCC.COM (3.2/STP1.14) id AA16205; Wed, 30 Sep 87 17:18:12 CDT To: wilson@ji.Berkeley.EDU In-Reply-To: James E. Wilson's message of Wed, 30 Sep 87 11:21:20 PDT <8709301821.AA23038@ji.Berkeley.EDU> Subject: UNIX Moria Status: RO Hokay - the files are in place. The source file is pretty massive; I had to segment it into three pieces in order to fit it through our gateway machine. Just cat the segments together before unsharing. It's not compressed or anything. The best thing to do is copy all the shar files to the directory you want to install in, then unshar moria.shar first. There's a README that explains how to compile and install. The wizard passwords are a little hidden (just enough so that someone with the strings program can't find them easily). They are DeadlyBalrog and MoriaDungeon. Capitals count, no carriage return needed. --Alan From @MCC.COM:wex@MCC.COM Wed Sep 30 11:35:53 1987 Received: from MCC.COM by ji.Berkeley.EDU (5.58/1.25) id AA23167; Wed, 30 Sep 87 11:35:49 PDT Received: from milano.SW.MCC.COM by MCC.COM with TCP; Wed 30 Sep 87 13:35:31-CDT Received: from banzai-inst by milano.SW.MCC.COM (5.52/STP1.51) id AA17587; Wed, 30 Sep 87 13:35:26 CDT Date: Wed, 30 Sep 87 13:35:12 CDT From: Buckaroo Banzai Message-Id: <8709301835.AA14738@banzai-inst.SW.MCC.COM> Received: by banzai-inst.SW.MCC.COM (3.2/STP1.14) id AA14738; Wed, 30 Sep 87 13:35:12 CDT To: wilson@ji.Berkeley.EDU In-Reply-To: James E. Wilson's message of Wed, 30 Sep 87 11:21:20 PDT <8709301821.AA23038@ji.Berkeley.EDU> Subject: UNIX Moria Status: RO > >You also seem to have the problem that's been plaguing me - monsters > >aren't always visible when they ought to be, especially in dark rooms > >and corridors. I think there's something wrong in draw_block(). > >Drat! I was hoping you'd solved that one. > I have never noticed this. Could you be a little more specific? > How can I reproduce this? Go to any dark room (preferrably with a human character so infravision doesn't mess things up) and wander around. Sometimes you'll be right next to a monster but be unable to see it. It also happens in corridors, if you bump into a monster unexpectedly. You get messages like "You hit it," when you should get messages with the monster's name. I've tracked the problem down to the 'ml' field in the monster record. Y'see, draw_block() redraws the area around the player, but doesn't always set that field when it should. I'd like to find a VMS version to play with and see if it works, but I haven't been able to get the VMS code I have to run, and I don't know the wizard passwords for it either :-( Re: passwords. Nope. I just went back and tried again - ^p and ^P don't ask for the password. I've compiled it on my Sun3 - have you tried it on that machine yet? > >The rogue-command interface is really kludgey - I'm going to hold off > >installing that in my code for a while. > Yeah, sort of, but it IS nice if you don't have a numeric keypad. I guess. it didn't take me long to adjust, but then I don't play rogue/hack much anymore. I'm thinking of including a patch to handle the Sun's keypad (which generates weird escape-strings). > The signals are some of the most important code. I never would have > gotten any serious playtesters if they lost games due to bugs. > I had some people fighting the Balrog even with buggy versions of the > game, because they did not have to start all over again every time the > program crashed. (anecdotal evidence: my first game of xconq was lost > due to a floating point exception, I immediately added signal handlers > to save games before core dumping, this proved useful during my second game :-) I guess. I was too embarrassed to let other people use the code while it crashed like that. For myself, I just used wizard mode and dbx to regenerate games that got blown away by bugs. Want to ship me your diffs to xconq? I'm getting tired of having it core dump on me all the time. I will try putting my files on ucbarpa and let you know when they're there. --Alan moria-5.6.debian.1/misc/README0000644000175000017500000000075105613574234014012 0ustar pjbpjbstuff that isn't part of Umoria, but would be nice if it was funckeys.h, funckeys.c, mabbrev are (mama) Liz's code for handling SUN keypads shading is joseph n hall's ideas on how to efficiently calculate multiple lines of sight haggle.sug, moria.msg, and mail.msg are some interesting mail messages about moria which suggest changes or additions rick.msg is a mail message from the author of VMS Moria 6.0, which lists the changes he was working on, VMS Moria 6.0 seems to be defunct moria-5.6.debian.1/misc/funckeys.h0000644000175000017500000000212605613574235015131 0ustar pjbpjb/* funckeys.h*/ /* default mappings for SUN-3 function keys */ #define FCHAR '[' char keyarray[50]; char rkeys[] = { INPUT_ERROR, /* nothing */ INPUT_ERROR, /* r1 */ INPUT_ERROR, /* r2 */ INPUT_ERROR, /* r3 */ '7', /* r4 */ '8', /* r5 */ '9', /* r6 */ '4', /* r7 */ '5', /* r8 */ '6', /* r9 */ '1', /* r10 */ '2', /* r11 */ '3', /* r12 */ INPUT_ERROR, /* r13 */ INPUT_ERROR, /* r14 */ '.' /* r15 */ }; char lkeys[] = { INPUT_ERROR, INPUT_ERROR, /* l1 */ INPUT_ERROR, /* l2 */ INPUT_ERROR, /* l3 */ INPUT_ERROR, /* l4 */ INPUT_ERROR, /* l5 */ INPUT_ERROR, /* l6 */ INPUT_ERROR, /* l7 */ INPUT_ERROR, /* l8 */ INPUT_ERROR, /* l9 */ INPUT_ERROR /* l10 */ }; char fkeys[] = { INPUT_ERROR, INPUT_ERROR, /* f1 */ INPUT_ERROR, /* f2 */ INPUT_ERROR, /* f3 */ INPUT_ERROR, /* f4 */ INPUT_ERROR, /* f5 */ INPUT_ERROR, /* f6 */ INPUT_ERROR, /* f7 */ INPUT_ERROR, /* f8 */ INPUT_ERROR, /* f9 */ }; moria-5.6.debian.1/misc/rick.msg0000644000175000017500000003442405613574235014577 0ustar pjbpjbFrom 18862246%VUVAXCOM.BITNET@lilac.berkeley.edu Thu Aug 24 13:11:19 1989 Received: from lilac.Berkeley.EDU by ernie.Berkeley.EDU (5.61/1.36) id AA06320; Thu, 24 Aug 89 13:11:14 -0700 Received: by lilac.berkeley.edu (5.61.1/1.16.22) id AA05399; Thu, 24 Aug 89 12:47:05 PDT Message-Id: <8908241947.AA05399@lilac.berkeley.edu> Date: Thu, 24 Aug 89 15:41 EST From: "Computers and you, living life a bit at a time" <188622462%VUVAXCOM.bitnet@lilac.berkeley.edu> Subject: Here is the UPDATE.TXT file To: wilson@ernie.Berkeley.EDU Original_To: BITNET%"wilson@ucbernie" Status: RO Here are the changes incorporated to date in the upgrade from V5.0 to V6.0: o The source code has been converted from a %INCLUDE format to modular programs. Due to low system memory quotas set on student accounts at my university, compiling the %INCLUDE form was not possible. By converting to modular form, anyone with enough disk space can compile the program, by compiling each module separately, and then linking all the files together. Along with this, I also changed all the indentation in the code so that it is uniform throughout, something that was not there from having four or more different people work on it before. o Creation of a new high score list. Early in Moria's time at my node, many people had found out the Wizard mode password (this was for version 4.3 and then 4.8), so I have created a Wizard Mode Top Twenty list. Part of this has been creating 2 new fields in the player character record to enable Moria to remember if your character ever entered Wizard or God modes. If you used Wizard mode at any point, you are eligible for the Wizard mode list, if you used God mode, you can't get on any list. If you die and aren't allowed to go to either of the lists, the game does tell you what score you earned. o A second effect of everyone here knowing the Wizard password was the continual resurrection of characters by copying the save file and re- storing the character. This lead to multiple copies of the same character appearing on the high score lists. I have solved this problem by adding two more new fields to the character record, to keep track of the birthdate and birthtime of the character, taken from the system time at the same point that the stats are rolled. When a character dies, his birthdate/time is recorded in the highscore file, and whenever that same userid kills another character, it checks to see if the birthdate/times match, if so, then it assumes a clone, and doesn't post the score to the list. The game does tell you what you had earned in this case. o The game now saves the userid of the character's creator in the save file. This prevents one person making a strong character, then giving it to someone else to use to finish off the Balrog. o The increase of stats via special items (ie: HA increasing strength) and via Gain potions has been re-worked. Increase stat items (weapons, rings, crowns, amulets, armor) now affects only the current value of the stat, not the max value. Gain potions affect the max and the current, based on the max value. If you are close to 18/100 and the item would increase you past that, you will see a drop in the current value of the stat when you take it off, but a Restore potion will return you to what it was before you wielded/wore the item. o The changing of the cost of an item has been repaired where an increase to the tohit and todam values are concerned. Also, changes have been implemented wherever items are damaged, so that the shops will know of their decreased value. o The Vampire Bites attack has been modified. Originally, you lost the same amount (or close to it) of hit points as you did experience points (which could be from 18d8 to 32d8, depending on the type of Vampire). The Vampire Bite now takes off 1d6 hit points (logic: you bleed a bit). o The stats area (left side of screen) has been fixed in regards to field widths. All fields, when re-printed, wipe out any extra digits from the previous value. If you have more than 9,999,999 in gold, the string "$$$$$$$" is printed. If more than 9,999,999 experience points are earned, the string "*******" is printed. If you have more than 999 mana then the string "###/###" will be printed. o The God mode function ^C (Make Nice Character) now checks to see if the character is a Magic-using type (ie: not Warrior or Rogue) before upping the mana score. The God function ^E (Change Character) does the same. o A new wizard function: Describe Object. This will give you information about the item specified, including Damage, Tohit and ToDam adjustments, weight, and others. This will not identify an unidentified item, only help you in figuring out if one item is better than another (ie: which sword does more damage?). The hex flags for the item in question will be translated to show what special magic is inherit in the item. o A new God Mode function, ^X, Examine Character. This prints out all the values of the Flags section of the player character record. Useful in debugging purposes. o A bug with Search mode and going up/down stairs has been fixed. When using stairs, Search mode is turned off (if it was on) and the relevant reduction in speed is removed. o All code referring to the "Consultant" classes and the "Extra" spells group have been removed, since a) they were written, but no character race was allowed to be one and b) they were simply slight modifications on the mage class. o In the source, there were two people who used their initials as parts of variable names. These have all been changed to more descriptive names. o The Town generation code has been fixed so that any store could appear at any of the locations, instead of the Black Market always appearing in the upper right-hand corner. The code there has also been fixed so that adding in additional stores should not be difficult. o The various spell books have been fixed so that multiple copies will be listed as "a) 2 Books of " in the inventory list. o The running of the Black Market has been fixed up so that it works more like the other stores, except store inventory turn-around is still as as fast as it was before. The inventory will now flucuate in size, just as the other stores do. o A bug involving the Wizard Mode Light Dungeon function and using a torch has been repaired so that the tunnel floors remain lit after passing over them. o Caps/Helms of Intelligence/Wisdom bought in the Black Market now correctly increase the relevant stat. o A bug involving certain area-affect spells (Light Area, any Ball-type spell, etc) and the right-hand and bottom edges of the town level has been fixed. o The magic translation case statements in SCROLLS.PAS and POTIONS.PAS has been fixed to allow a full set of both to be used. Previously, each one was coming up short of the 64 actual possible slots that are available by using two Tval values. o The problem with the special Magic and Prayer books from the Black Market has been fixed so that they appear as separate items in your inventory and are not added with the normal books. o The bug concerning enchanting items bought from the Black Market and the new values never being seen was been repaired, so that the name string of the item will be displayed properly. o The Control-Y exit command has been changed so the user has to hit Q to exit instead of Y. This is to make it more fool-proof and more accident proof (but not totally). o Three new monster attacks: Lose Mana (different from the monster spell), Slip, Trip, and Fall (you'll find out), and Eclipse attack. A number of new attack descriptions have been added with this. A new function was added, function DEX_ADJ, to determine the character's plus or minus to his dexterity saving throw. o New monsters have found their way into the Dungeons of Moria. A list of their names can be found in the file MONSTERS.NEW, included in the distribution package (or from your local Moria Wizard). o The creatures "Mother & Baby" and "Small Girl" have been fixed to correctly utilize the CDEFENSE flag of Lose Experience for killing that creature. o The global constant store$turn_around has been changed to the global array variable store_turnaround, allowing each store to have a different inventory turn over rate. This was done partially to work the Black Market in more properly. o A bug involving the running function ('.' and a direction) has been fixed so that if you are attacked in any form, either via a physical hit or a spell, you will stop running at that point. o New monster defense: cloning on death. A new value has been added to the CDEFENSE flag so that certain monsters can try to clone themselves when they have been dealt a mortal blow. There are four types of cloning, each giving a different base chance to clone. The chance is reduced based on how badly killed the creature is (if you "neutronize" the critter, he isn't as likely to clone himself). o The \ function has been fixed up a bit, mainly in formatting control, with an added piece to watch for the end of the screen and page it out as needed. Also, it has been renamed to ^U, and is now a Wizard mode function, just as creating the Monster Dictionary is. o The Create Food spell/scroll has been fixed. If an item is under you when you cast/read this spell, it will not be deleted as it was doing before. Make sure you have a open space of floor under or around you, or you may go hungry... o The Medusa has been fixed so that it's gaze causes Turn to Stone, not Vampire Bite. o Added a new flag to the monster's spell flags. A creature can now be set up so that only a percentage of that type of creature will be spell casters, assuming the type has any spell ability at all. For example, the Young Blue Dragon could be set up so that only 1 in 10 Young Blue Dragons can cast spells at all. This does not effect Dragon Breath attacks, only spell ability. If a zero or one is in this position, all members of that creature type can cast spells, if any are indicated. From 18862246%VUVAXCOM.BITNET@lilac.berkeley.edu Thu Aug 31 06:10:59 1989 Received: from lilac.Berkeley.EDU by ernie.Berkeley.EDU (5.61/1.36) id AA14710; Thu, 31 Aug 89 06:10:54 -0700 Received: by lilac.berkeley.edu (5.61.1/1.16.22) id AA04291; Thu, 31 Aug 89 05:54:29 PDT Message-Id: <8908311254.AA04291@lilac.berkeley.edu> Date: Thu, 31 Aug 89 08:51 EST From: "Charon, the Ferryman on the River Styx" <188622462%VUVAXCOM.bitnet@lilac.berkeley.edu> Subject: what to put for a subject? I don't know... To: wilson@ernie.Berkeley.EDU Original_To: BITNET%"wilson@ucbernie" Status: RO Jim- I see what you mean about the up/down and the search flag thing. What did you add to the main dungeon procedure to fix this? At the end of this letter, I've appended the dictionary descriptions of the "Mother & Baby" and "Small Girl". I've also include the piece from the mon_take_hit function that checks the appropriate bit in the monster cdefense flag. I believe this was something written in for the 5.0 UB version, but I'm not certain, so if you need more to be able to put it into yours, I can send whatever you need. That bug you mention could well be the result of someone diddling with the sources. Off hand, I can think of one or two reasons they'd do something to the monster-array parts, to save on memory usage, but the file-access goes way up the minute you do anything other than the orginial form, so you lose out in the end. I'll keep my eye out, but I doubt if I'll ever see it happen here. Sounds like you and I, and the rest of the Usenet community, are in agreement then. We'll keep our two separate "schools" of Moria, and just share thoughts back and forth. Now if only the VM/CMS Moria porter would respond to my letter... Catch you later, Rick ---excerpt from function mon_take_hit. Insert within the section of if statement that has determined the monster has died. EXP is the player's current experience points. LEV is the player's level. I1 is the amount of experience the creature is worth (I think it's a calculated value) {Penalize player - subtract experience} if (uand (cdefense, %X'00000400') <> 0) then begin exp := exp - 10*lev; if (exp < 0) then exp := 0; end else exp := exp + i1; -------------------------------------------- 1 Mother and Baby (p) Speed = 1 Level = 0 Exp = 0 AC = 1 Eye-sight = 4 HD = 1d1 Creature harmed by cold. Creature harmed by fire. Creature harmed by poison. Creature harmed by acid. Creature harmed by stone-to-mud. Causes experience loss when killed Creature seen with Infra-Vision. Creature picks up objects. --Spells/Dragon Breath = --Movement = Moves and attacks normally. 20% random movement. Can open doors. --Creature attacks = Touches you for normal damage. (0d0) -------------------------------------------- 2 Small Girl (p) Speed = 1 Level = 0 Exp = 0 AC = 1 Eye-sight = 4 HD = 1d1 Creature harmed by cold. Creature harmed by fire. Creature harmed by poison. Creature harmed by acid. Creature harmed by stone-to-mud. Causes experience loss when killed Creature seen with Infra-Vision. Creature picks up objects. --Spells/Dragon Breath = --Movement = Moves and attacks normally. 20% random movement. Can open doors. --Creature attacks = Touches you for normal damage. (0d0) -------------------------------------------- moria-5.6.debian.1/misc/mail.msg0000644000175000017500000005161205613574234014566 0ustar pjbpjbFrom afc@klaatu.cc.purdue.edu Tue Jan 16 13:33:16 1990 Received: from klaatu.cc.purdue.edu by ernie.Berkeley.EDU (5.61/1.36) id AA09793; Tue, 16 Jan 90 13:33:09 -0800 Received: by klaatu.cc.purdue.edu (5.61/1.14) id AA01432; Tue, 16 Jan 90 16:32:51 -0500 Date: Tue, 16 Jan 90 16:32:51 -0500 From: afc@klaatu.cc.purdue.edu (Greg Flint) Message-Id: <9001162132.AA01432@klaatu.cc.purdue.edu> To: wilson@ernie.Berkeley.EDU Subject: Some comments about PC Moria 4.873 aimed toward your Moria 5.0 Status: RO You comment that Umoria 5.0 will have good balance because it will be player tested before its release. I'd be willing to volunteer to do some of this beta testing. I don't have lots of time to play but I find moria to be a good way to unwind after a long day fighting more mundane mosters such as Vaxes, Cybers and Suns. A few opinions about PC Moria 4.873 that might influence Umoria 5.0: STATS ----- * Once stats get to the 18/xx stage, I find that I can deal with almost anything non-hastened (except for MHD's and Green d/D's) because by then my HP's are usually quite high. I can just hack away and usually come out on top. If I have sufficient haste self, I tackle V's and L's. If I don't, I phase door, teleport away or run for the stairs. (The method depends on my character type, distance from the monster and equipment at hand.) * After I reach the 18/xx stage, the game degenerates in to a sequence of 1) attack until I loose life levels, 2) WOR to store level, 3) buy more WOR and RLL, if available, 4) kill time on level 1 if no RLL, then back to #3 5) WOR back to deepest level, 6) go to #1". until I'm finally ready to go to level 50 of the dungeon. MONSTERS -------- * It seems to take "forever" to go up the levels of 32+ because there is a big disparity between the value of monsters and the amount of points needed to rise to the next level. I find myself looking for D's (and L's if I've the proper abilities and/or tools) and being bored by almost anything else -- and yet I'm not yet ready for Iggy or the big "B". MAGIC ----- * Maybe I've been lucky, but I've always been able to find some "see invisible" item early (about Banshee dungeon level). This makes G's, L's, etc a lot easier (see the earlier comment on my playing sequence.) * When playing as a mage and reaching about level 29 where I gain fire ball, I find that I've reached the peak in spells. Of the two spells after that, I've never used WOD and find Genocide so powerful that it seems like cheating. STORES and MONEY ---------------- * Money is an issue early, but once I get to about 10,000, I never need to worry about money again -- for two reasons. The scrolls, potions, staves and the like are cheap (relative to 10K gold). The weapons that are HA, DF, etc almost never appear so even though they are expensive, I never seem to need the money. * It would be nice to know how may of a given item are in a store. This would help with questions such as "should I buy now or wait and chance that it (they?) are gone next time?" or "can I buy him out in the hopes of getting better stock next time?". MAGE SPELLS ----------- * The two recharge and the three sleep spells seem redundant (especially the latter). I usually ignore the Level I recharge and Levels I and II sleep spells because I need more offensive weaponry (spells). By the time I get around to learning these low level spells (because I've moved up a mage level and you've got to pick something), I really don't need them. * I don't know what I'd suggest, but I'd like to see some other spells in place of the ones listed above -- especially some after level 29. * How about spells being fixed in terms of there letter? Nothing is more painful than forgetting that I've added spell "b" thereby making spell "e" spell "f" and wasting a bunch of mana and maybe allowing a monster a free hit. MAP --- * I find the reduced map a help in speeding up the game. I favor anything that speeds up the game at no penalty me. (For example, using "H" to "run" in place of lots of h's is a no cost plus. I would not want to be penalized for "running" since all I'm doing is speeding up the game, not trying to "tire out" the character.) ------------------------------------------------------------------------------ Greg Flint Math G-169 (317) 494-1787 UUCP: purdue!klaatu.cc!afc Purdue Univ. Purdue University INTERNET: afc@klaatu.cc.purdue.edu Computing Ctr. West Lafayette, IN 47907 BITNET: flint@purccvm.bitnet From qqc@h.cc.purdue.edu Thu Jan 18 13:54:52 1990 Received: from h.cc.purdue.edu by ernie.Berkeley.EDU (5.61/1.36) id AA09437; Thu, 18 Jan 90 13:54:47 -0800 Received: by h.cc.purdue.edu (5.61/1.14) id AA15380; Thu, 18 Jan 90 16:54:08 -0500 Date: Thu, 18 Jan 90 16:54:08 -0500 From: qqc@h.cc.purdue.edu (Dale Forsyth) Message-Id: <9001182154.AA15380@h.cc.purdue.edu> To: wilson@ernie.Berkeley.EDU Subject: program comments Status: RO Jim Wilson: As I perceive you as the author/programmer now associated with moria, I have several comments to make, in light of messages you have posted in the past about the program. I use the ibm-pc version 4.873, but expect my comments apply universally. All the following is, of course, only one person's opinion. I'm almost ashamed to admit how much I've used the program -- suffice to say I consider myself VERY experienced. I think I could win with ANY character, but I would not have the patience to do so. I consider the ONLY reason to use the program is for my own enjoyment. Any cheating I do is only to myself, for myself, and affects no one else; of course mine isn't a multi-user machine, for which you are concerned. In my opinion, a mage is a reasonable and fun character. I don't think it should be necessary to change it's balance. A priest (current character) is ok EXCEPT that it needs an identify spell. Either that or the shops MUST keep identify spells stocked. Since they do not in my version, I would quit this character as NOT FUN anymore, except that I use wizard mode and cheat on this point. I do NOT consider the 'triangle dance' around monsters a bad thing. I think there SHOULD be a way to outdo monsters that are bigger and badder than you, if you have patience. The shops is an area that needs improvement; they should contain better and better things as one's level increases. After a while there becomes NO REASON to return topside and accumulation of gold becomes moot. It would stay more FUN if you could BUY that HA weapon, even at 300,000 gp, when you have only 175,000 gp. But really good stuff never appears in MY shops. Endless repetition of mundane tactics that you know, waiting for something you NEED, is NOT FUN. A little is ok, month's of my life that way is NOT FUN. Characters beyond the BALROG would be possible, as for example Mordred from Mordor (Lord of the Rings), the Ring Wraiths, etc. I think reincarnation, perhaps with some penalty, would be I think reasonable. (Me, I cheat with backups, to learn, try things that if I knew I couldn't get back I just wouldn't do, and therefore wouldn't have that particular fun, etc). If one thing is over-powerful, it's perhaps bashing for good characters. When I am REALLY ready to take on the balrog, (not try it for FUN with a worse character), I accomplish his demise, fully loaded with mana, equipment, etc, none of which I need or use, and he dies without ever touching me. Of course this takes searching for months for enough speed, but bashing is the secret (as I know you know) and reduces the game to trivial at that point. (3 AMHD's at one time, all always stunned, none ever hurting you; that's an example). My main points in this letter are Priests and others need Identify or stores must keep scrolls, to be fun, and stores should stock better, more expensive things as one progresses. Thanks for maintaining such a good program, one of the most addictive I know. Dale Forsyth (45 yr-old game addict) qqc@h.cc.purdue.edu From ucbvax!tut.cis.ohio-state.edu!cs.utexas.edu!yale!cs.yale.edu Status: RO Article 4187 of rec.games.moria: Path: ucbvax!tut.cis.ohio-state.edu!cs.utexas.edu!yale!cs.yale.edu! >From: berman-andrew@CS.Yale.EDU (Andrew Berman) Newsgroups: rec.games.moria Subject: Possible Enhancements Message-ID: <12615@cs.yale.edu> Date: 24 Jan 90 03:52:46 GMT Sender: news@cs.yale.edu Reply-To: berman-andrew@CS.Yale.EDU (Andrew Berman) Organization: Yale University Computer Science Dept, New Haven CT 06520-2158 Lines: 47 I've been playing moria off and on for several years, only recently with version 4.87. I have some suggestions which I'd like input on. Most of them would make the game *harder*, but would also increase the power and attractiveness of some classes, like the fighter, which don't get used as often. The first suggestion is to give fighters limited poison immunity. Let them take a % damage which diminishes with their level, up to, say 1/2 damage for a level 39 character. So they won't get blown away like other characters by AMHD. They have enough problems as it is. And it's somewhat consistent- a fighters training may include ducking blasts, holding their breath, keeping their skin from being exposed, etc... The second suggestion is to limit the power of the "cure poison" *spell* of the mages and priests. Right now, you can fight a black mamba and kill it without looking at your stats, because a simple relatively low level spell will eliminate any future problems. Keep the potion as currently powered, though. The third suggestion is to limit weapons and Armor based on character class, like in D & D. I see no reason to allow a Priest full use of an Executioner's sword, no matter what his/her strength/dex. If a Priest uses an edged weapon, have some sort of minus. If a Mage tries to cast a spell through Plate Armor, decrease chance of success. If a Rogue uses a dagger, give a +3 to hit bonus. Fighters and Paladins can use anything. Rangers get double damage with bows. Something like that. My fourth suggestion is to limit max stats based on character race and maybe on character class. The point of the previous two suggestions is to eliminate the demigodlike character, a 250 hitpoint, 4-hits-per-round-with-a-Beaked-Axe, armor class of 58 character elven mage. My fifth suggestion is to allow "disenchanting" creatures to occasionally zap an ego weapon, low probability, but maybe "you hear your longsword scream in agony" as it goes from an HA to zip. My sixth suggestion is to give critical hits to monsters. Let a Bezerker occasionally get a good one in for triple damage. Let a touch have a 5% chance of being a grasp for double drain.. Any comments? From ucbvax!decwrl!lll-winken!uwm.edu!cs.utexas.edu!tut.cis.ohio-state.edu Status: RO Article 4188 of rec.games.moria: Path: ucbvax!decwrl!lll-winken!uwm.edu!cs.utexas.edu!tut.cis.ohio-state.edu >From: mf2t+@andrew.cmu.edu (Matthew David Fletcher) Newsgroups: rec.games.moria Subject: Re: Possible Enhancements Message-ID: Date: 24 Jan 90 05:08:34 GMT References: <12615@cs.yale.edu> Organization: Carnegie Mellon, Pittsburgh, PA Lines: 35 In-Reply-To: <12615@cs.yale.edu> berman-andrew@CS.Yale.EDU (Andrew Berman) writes: >The first suggestion is to give fighters limited poison >immunity. Let them take a % damage which diminishes with their level, >up to, say 1/2 damage for a level 39 character. So they won't get >blown away like other characters by AMHD. They have enough problems >as it is. And it's somewhat consistent- a fighters training may >include ducking blasts, holding their breath, keeping their skin from >being exposed, etc... > >The second suggestion is to limit the power of the "cure poison" *spell* >of the mages and priests. Right now, you can fight a black mamba and >kill it without looking at your stats, because a simple relatively low >level spell will eliminate any future problems. Keep the potion as >currently powered, though. My current character is a twenty third level half-troll warrior. The only time I've come close to dying while being poisoned was when the Stone Giant came up and started pounding me half way through. Certain races are naturally suited to certain classes by virtue of their beginning stats. Are mages capable of casting spells while afraid. If so, a natural resistance to fear would make it more even. A ghost almost killed me a while ago, because I couldn't attack it. >My fifth suggestion is to allow "disenchanting" creatures to occasionally >zap an ego weapon, low probability, but maybe "you hear your longsword scream >in agony" as it goes from an HA to zip. This could be rather expensive, considering the cost of all the computer equipment that would be destroyed when a person's dagger (HA) (+8,+8) gets zapped. Fletch From ucbvax!tut.cis.ohio-state.edu!zaphod.mps.ohio-state.edu!unix.cis.p Status: RO Article 4193 of rec.games.moria: Path: ucbvax!tut.cis.ohio-state.edu!zaphod.mps.ohio-state.edu!unix.cis. >From: dtate@unix.cis.pitt.edu (David M Tate) Newsgroups: rec.games.moria Subject: Re: Possible Enhancements Message-ID: <21833@unix.cis.pitt.edu> Date: 24 Jan 90 17:00:57 GMT References: <12615@cs.yale.edu> Reply-To: dtate@unix.cis.pitt.edu (David M Tate) Organization: Univ. of Pittsburgh, Comp & Info Services Lines: 35 Andrew Berman lists a number of possible enhancements for later versions of Moria. Some of them, I think, bear serious consideration. In particular, I think that the idea of distinguishing various character classes even more sharply is a good one. I agree wholeheartedly that the only weapons usable by a priest should be mace/morningstar/hammer/club/flail types. No one but a fighter, paladin, or ranger should be able to wield a 2-handed sword or Executioner's Sword. No matter how strong a mage gets, he should not be able to fight effectively with anything heavy, nor able to cast spells effectively while wearing heavy armor. One way to reduce the mage/ranger advantage would be to implement a "setup cost" for the switch between magic mode and fighting mode: you can't cast a spell in the round immediately following a slash/fire move. This makes some sense, as one would in general have to "prepare" a spell before casting it. Similarly, one would expect the act of praying to take some finite time. (For that matter,eating should take some time--a character interrupted while eating would have the option of finishing the meal (while getting stomped) or abandoning it (in which case the remainder is lost--trampled in battle, or some such). One touch of realism that I would like to see is more more NPC's to pick up things. I know this can be done, because ghosts do it already. Can you really imagine a hobgoblin coming into a room and *not* picking up the gold and gems? This would add the challenge of preserving items to the character. Similarly, why can't you get your stolen gold back from a dead rogue? What did he do with it? Hide it? If you're a rogue yourself, you should be able to (a) keep him from picking your pocket, and (b) find where he hid it. Just a few ramblings... -- ============================================================================== David M. Tate | "I do not know which to prefer: the beauty dtate@unix.cis.pitt.edu | of inflections, or the beauty of innuendoes; | the blackbird whistling, or just after..." From 73230.224@compuserve.com Tue Jan 30 11:46:30 1990 Received: from saqqara.cis.ohio-state.edu by ernie.Berkeley.EDU (5.61/1.36) id AA23367; Tue, 30 Jan 90 11:46:14 -0800 Received: by saqqara.cis.ohio-state.edu (5.61/4.891221) id AA09041; Tue, 30 Jan 90 14:45:48 -0500 Date: 30 Jan 90 12:41:49 EST From: Curtis McCauley <73230.224@CompuServe.COM> To: Subject: Umoria 5.0.13 disks mailed Message-Id: <"900130174148 73230.224 EHA20-1"@CompuServe.COM> Status: RO To: >INTERNET:wilson@ernie.Berkeley.EDU I mailed you the sources either Monday or Tuesday of last week. I can't remember which day for sure. I used regular mail, so it may take some time. The mailing required two diskettes, one for the source, the other for a compiled version of the game. Do you have access to MPW 3.0? You will need it to compile. I don't think that THINK C could be used very easily in place of MPW. I rely pretty heavily on the MPW environment to make the program. While I'm thinking about it, there are a couple of principles which, if observed in all parts of the code, would make the mac port easier and less of a hack: 1) Don't modify a variable which is initialized in its declaration (e.g., "int foo_flag = TRUE"). I had to try to find all of these in order to make the game restartable. 2) Don't rely on the value of a variable which is not initialized in its declaration being zero. For example, get_panel() forces the panel to be redrawn the first time it is called in the course of a game because panel_[row/col]_[min/max] are all zero. In the mac version, when the game is restarted, these variables have the values left over from the previous game. I do with them what I do with the variables which fall under 1 above: I keep their "initialized" value in a resource and restore them each time a game is restarted. 3) (This follows a fortiori from 1 above.) Don't modify a private variable which is initialized in its declaration. These I had to move from the source files in which they were declared to variables.c and externs.h in order to make them accessible for the routines which build the restart resource and copy the saved data when a new game is started. Admittedly, there is some inconvience involved in following these rules. It's a judgement call. The version I have given you "hilights" the veins instead of using '%'. I didn't discover that you had given up on hilighting until after I had ported io.c to allow it. So I figured I'd leave it in. I discovered after I had sent you the game that this causes the map command to screw up because it doesn't know how to handle -'#'. What do you think? Remove the hilighting capability or fix the map command to handle it? You might want to consider the possibility of having two mac file types for save files: one for living characters, another for dead characters' memories. This way the two files will be distinguishable by their icons. (Perhaps a tombstone as the latter type of icon.) Do we want to get a new application signature from Apple? I'd prefer not to, but there likely will be problems for people who try to keep the old version around on their disks. For example, I am not certain which program will come up if the user double clicks on a save file from the finder when he has both copies of the game on his disk. Maybe this can be handled by simply telling the player to throw away his old version in the mac help text. I do not like the way the game "flows" at the end, particularly the standard file dialog which prompts for saving the player's memories. It seems kind of intrusive. I do not know how things will change when the top ten is added. Also, there is a problem with the prompt in this dialog box. In save_char() I try to say "Save your memories as:" instead of "Save the game as:" when I think the player has died or quit. This doesn't always work right. Sometimes it says "memories" when it should say "game". This always happens when ^X is used to save the game. I have fixed that problem since I sent you the source. Another problem remains: I rely upon the variable death to decide which prompt to choose. This will not work when the player quits the character. Death is not set, yet only the memories will get saved, right? In the version you have, I have the two prompts switched in save_char(). So, you get the "memories" prompt when you quit and the "game" prompt when you are killed. Finally, do female dwarves really have beards? Ugh. -Curtis (73230.224@compuserve.com) From chinet!saj@gargoyle.uchicago.edu Mon Feb 5 23:29:25 1990 Received: from gargoyle.uchicago.edu by ernie.Berkeley.EDU (5.61/1.36) id AA00727; Mon, 5 Feb 90 23:29:21 -0800 Received: by gargoyle.uchicago.edu (5.59/1.14) id AA06383; Tue, 6 Feb 90 01:28:53 199 Received: by chinet.chi.il.us (/\=-/\ Smail3.1.18.1 #18.65) id ; Tue, 6 Feb 90 00:27 CST Message-Id: From: saj@chinet.chi.il.us (Stephen Jacobs) Subject: Source arrived today To: ernie.Berkeley.EDU!wilson@gargoyle.uchicago.edu (James E. Wilson) Date: Tue, 6 Feb 90 0:27:26 CST In-Reply-To: <9002020111.AA22413@ernie.Berkeley.EDU>; from "James E. Wilson" X-Mailer: ELM [version 2.2 PL16] Status: RO The source arrived today. Thanks. I've barely begun to scan it, but I'd guess that there shouldn't be any special problems bringing it up on the ST. One immediate suggestion: the Mark Williams C compiler defines the macro GEMDOS, and defines the macro __STDC__ to be 0. Using those as conditions could make recognition of the situation automatic. Steve J. moria-5.6.debian.1/misc/mabbrev0000644000175000017500000000245605613574235014500 0ustar pjbpjbglobal ESC-[-2-1-0-z R3 ESC-[-2-0-2-z L8 ESC-[-2-3-1-z F5 ESC-[-2-3-6-z F8 ESC-[-M-A DoubleMouseLeft ESC-[-M-B DoubleMouseMiddle ESC-[-M-C DoubleMouseRight ESC-[-2-2-0-z R13 ESC-[-2-1-2-z R5 ESC-[-2-0-4-z L9 ESC-[-M-^A MouseLeft ESC-[-2-3-3-z F6 ESC-[-M-^B MouseMiddle ESC-[-2-2-5-z F2 ESC-[-M-^C MouseRight ESC-[-2-0-9-z R2 ESC-[-M-^E ShiftMouseLeft ESC-[-M-^F ShiftMouseMiddle ESC-[-M-^G ShiftMouseRight ESC-[-1-9-4-z L2 ESC-[-M-^I CtrlMouseLeft ESC-[-M-^J CtrlMouseMiddle ESC-[-M-^K CtrlMouseRight ESC-[-2-0-1-z L7 ESC-[-M-^Q MetaMouseLeft ESC-[-M-^R MetaMouseMiddle ESC-[-M-^S MetaMouseRight ESC-[-2-2-2-z R15 ESC-[-2-1-4-z R7 ESC-[-2-0-6-z L10 ESC-[-2-3-5-z F7 ESC-[-2-2-7-z F4 ESC-[-1-9-6-z L4 ESC-[-2-1-1-z R4 ESC-[-2-2-4-z F1 ESC-[-2-1-6-z R9 ESC-[-2-0-8-z R1 ESC-[-2-3-7-z F9 ESC-[-2-2-9-z F4 ESC-[-1-9-8-z L5 ESC-[-M-! ModelineMouseLeft ESC-[-2-0-0-z L6 ESC-[-M-" ModelineMouseMiddle ESC-[-M-# ModelineMouseRight ESC-[-2-1-3-z R6 ESC-[-M-' ShiftModelineMouseRight ESC-[-2-2-6-z F3 ESC-[-M-) CtrlModelineMouseLeft ESC-[-A R8 ESC-[-2-1-8-z R11 ESC-[-B R14 ESC-[-C R12 ESC-[-D R10 ESC-[-1-9-5-z L3 normal-mode text-mode elec-c main main default default do do while while else else if if switch switch argc argc for for #d #define #i #include case case moria-5.6.debian.1/misc/damage.chg0000644000175000017500000002424005613574234015032 0ustar pjbpjbFrom grabiner@zariski.harvard.edu Sun Nov 18 11:55:11 1990 Received: from ernie.Berkeley.EDU by ylem.berkeley.edu (5.61/1.34) id AA19024; Sun, 18 Nov 90 11:55:09 -0800 Received: from brauer.harvard.edu by ernie.Berkeley.EDU (5.63/1.41) id AA04665; Sun, 18 Nov 90 12:02:59 -0800 Date: Sun, 18 Nov 90 15:03:18 EST From: grabiner@zariski.harvard.edu (David Grabiner) Message-Id: <9011182003.AA02675@brauer.harvard.edu> To: wilson@ernie.Berkeley.EDU Subject: Patch file fixed; now it compiles Status: RO I made some stupid typos in the patch file I sent you Friday. Now I have compiled the program with the revise patch file, and checked that it works. Here is the corrected patch file. *** misc2.c.~1~ Fri Nov 16 22:08:51 1990 --- misc2.c Sat Nov 17 00:10:07 1990 *************** *** 981,987 **** } } prt_num("+ To Hit ", m_ptr->dis_th, 9, 1); ! prt_num("+ To Damage ", m_ptr->dis_td, 10, 1); prt_num("+ To AC ", m_ptr->dis_tac, 11, 1); prt_num(" Total AC ", m_ptr->dis_ac, 12, 1); } --- 981,987 ---- } } prt_num("+ To Hit ", m_ptr->dis_th, 9, 1); ! prt_num("Damage Bonus", m_ptr->dis_td, 10, 1); prt_num("+ To AC ", m_ptr->dis_tac, 11, 1); prt_num(" Total AC ", m_ptr->dis_ac, 12, 1); } *************** *** 2253,2260 **** --- 2253,2273 ---- } } + /* Add damage bonus to weapon damage -DJG- */ + /* Damage bonuses have greater effect on larger weapon damages, + so that daggers are not the best weapons in the game. */ + int add_dam_bonus(dam, bonus) + register int dam, bonus; + { + /* Add 2 to dam, multiply by 1+(bonus/9), round off, subtract 2; + thus bonus is added unchanged to a damage of 7 points, halved + on 1d4 damage, and nearly doubled on 4d6 damage */ + return ((((dam+2) * (18+(2*bonus)) + 9) / 18) - 2); + } /* Special damage due to magical abilities of object -RAK- */ + /* Multipliers have been reduced here, but they now apply to + magical bonuses as well -DJG- */ int tot_dam(i_ptr, tdam, monster) register inven_type *i_ptr; register int tdam; *************** *** 2280,2286 **** /* Slay Dragon */ if ((m_ptr->cdefense & CD_DRAGON) && (i_ptr->flags & TR_SLAY_DRAGON)) { ! tdam = tdam * 4; r_ptr->r_cdefense |= CD_DRAGON; } /* Slay Undead */ --- 2293,2299 ---- /* Slay Dragon */ if ((m_ptr->cdefense & CD_DRAGON) && (i_ptr->flags & TR_SLAY_DRAGON)) { ! tdam = tdam * 5 / 2; r_ptr->r_cdefense |= CD_DRAGON; } /* Slay Undead */ *************** *** 2292,2298 **** && (i_ptr->flags & TR_SLAY_UNDEAD)) #endif { ! tdam = tdam * 3; r_ptr->r_cdefense |= CD_UNDEAD; } /* Slay Animal */ --- 2305,2311 ---- && (i_ptr->flags & TR_SLAY_UNDEAD)) #endif { ! tdam = tdam * 2; r_ptr->r_cdefense |= CD_UNDEAD; } /* Slay Animal */ *************** *** 2299,2311 **** else if ((m_ptr->cdefense & CD_ANIMAL) && (i_ptr->flags & TR_SLAY_ANIMAL)) { ! tdam = tdam * 2; r_ptr->r_cdefense |= CD_ANIMAL; } /* Slay Evil */ else if ((m_ptr->cdefense & CD_EVIL) && (i_ptr->flags & TR_SLAY_EVIL)) { ! tdam = tdam * 2; r_ptr->r_cdefense |= CD_EVIL; } /* Frost */ --- 2312,2324 ---- else if ((m_ptr->cdefense & CD_ANIMAL) && (i_ptr->flags & TR_SLAY_ANIMAL)) { ! tdam = tdam * 3 / 2; r_ptr->r_cdefense |= CD_ANIMAL; } /* Slay Evil */ else if ((m_ptr->cdefense & CD_EVIL) && (i_ptr->flags & TR_SLAY_EVIL)) { ! tdam = tdam * 3 / 2; r_ptr->r_cdefense |= CD_EVIL; } /* Frost */ *************** *** 2317,2323 **** && (i_ptr->flags & TR_FROST_BRAND)) #endif { ! tdam = tdam * 3 / 2; r_ptr->r_cdefense |= CD_FROST; } /* Fire */ --- 2330,2336 ---- && (i_ptr->flags & TR_FROST_BRAND)) #endif { ! tdam = tdam * 5 / 4; r_ptr->r_cdefense |= CD_FROST; } /* Fire */ *************** *** 2329,2335 **** && (i_ptr->flags & TR_FLAME_TONGUE)) #endif { ! tdam = tdam * 3 / 2; r_ptr->r_cdefense |= CD_FIRE; } } --- 2342,2348 ---- && (i_ptr->flags & TR_FLAME_TONGUE)) #endif { ! tdam = tdam * 5 / 4; r_ptr->r_cdefense |= CD_FIRE; } } *** moria2.c.~1~ Fri Nov 16 21:59:04 1990 --- moria2.c Sat Nov 17 00:10:04 1990 *************** *** 751,756 **** --- 751,757 ---- if (i_ptr->tval != TV_NOTHING) { k = pdamroll(i_ptr->damage); + k = add_dam_bonus(k, p_ptr->ptodam); k = tot_dam(i_ptr, k, monptr); k = critical_blow((int)i_ptr->weight, tot_tohit, k, CLA_BTH); } *************** *** 757,765 **** else /* Bare hands!? */ { k = damroll(1, 1); k = critical_blow(1, 0, k, CLA_BTH); } - k += p_ptr->ptodam; if (k < 0) k = 0; if (py.flags.confuse_monster) --- 758,766 ---- else /* Bare hands!? */ { k = damroll(1, 1); + k = add_dam_bonus(k, p_ptr->ptodam); k = critical_blow(1, 0, k, CLA_BTH); } if (k < 0) k = 0; if (py.flags.confuse_monster) *** treasure.c.~1~ Fri Nov 16 23:53:35 1990 --- treasure.c Sat Nov 17 00:10:06 1990 *************** *** 169,175 **** {"& Small Sword" ,0x00000000L, TV_SWORD, '|', /* 49*/ 0, 48, 22, 1, 75, 0, 0, 0, 0, {1,6} , 5}, {"& Two-Handed Sword (Zweihander)",0x00000000L, TV_SWORD, '|', /* 50*/ ! 0, 1000, 23, 1, 280, 0, 0, 0, 0, {4,6} , 50}, {"& Broken sword" ,0x00000000L, TV_SWORD, '|', /* 51*/ 0, 0, 24, 1, 75, -2, -2, 0, 0, {1,1} , 0}, {"& Ball and Chain" ,0x00000000L, TV_HAFTED, '\\',/* 52*/ --- 169,175 ---- {"& Small Sword" ,0x00000000L, TV_SWORD, '|', /* 49*/ 0, 48, 22, 1, 75, 0, 0, 0, 0, {1,6} , 5}, {"& Two-Handed Sword (Zweihander)",0x00000000L, TV_SWORD, '|', /* 50*/ ! 0, 1500, 23, 1, 280, 0, 0, 0, 0, {4,6} , 50}, {"& Broken sword" ,0x00000000L, TV_SWORD, '|', /* 51*/ 0, 0, 24, 1, 75, -2, -2, 0, 0, {1,1} , 0}, {"& Ball and Chain" ,0x00000000L, TV_HAFTED, '\\',/* 52*/ From grabiner@math.harvard.edu Sun Nov 25 14:41:25 1990 Received: from zariski.harvard.edu by ylem.berkeley.edu (5.61/1.34) id AA01764; Sun, 25 Nov 90 14:41:22 -0800 Date: Sun, 25 Nov 90 17:52:59 EST From: grabiner@math.harvard.edu (David Grabiner) Message-Id: <9011252252.AA04462@zariski.harvard.edu> To: wilson@ylem.berkeley.edu Subject: Re: When damage bonuses get added in Status: RO > In this patch, I also rewrote the damage code to add all bonuses and > then multiply, and compensated for the strengthening of ego weapons by > halving the extra multiplier; thus, in my patch, a SD weapon does 2.5x > damage, instead of 4x, and a FT does 1.25x, not 1.5x. > >This instantly makes all current spoilers obsolete, and will confuse a hell >of a lot of people. These same people have been confused by the present system. Until I checked the source code two weeks ago, I assumed that 2x damage meant 2x damage, so that a blow which would have done 15 would do 45 if the weapon was SU. I proposed this change in order to keep the actual effects, rather than the multipliers, comparable. >On the other hand, reducing the pluses for EGO weapons >seems less confusing since it won't obsolete the spoilers list and is less >noticable to the players. I would like a good reason before making your >change; I will have to think about this. A change of this magnutude >should probably include a change to the minor version number, i.e. 5.3.0 >to make it easier to remember where the change occurs. If the pluses for ego weapons are reduced, the effect won't be that great, because you can always enchant an ego weapon up to about +8. Also, strength and ring of increase damage bonuses will still be multiplied. In particular, SU and SD will become much more powerful no matter what is done. A typical SD, say 2d6, +8, does 15 normally, 36 to dragons, under the old system. It would do 36 to dragons under the new system even if its damage bonus were reduced to +2 (adding -3 instead of +3 when the ego weapon was generated), and at +2, it would be very easy to enchant. And this does not even consider the fact that SD weapons are usually wielded by players who have high strength and damage bonuses from other items. It would be possible just to weaken ego weapons by removing all of their extra bonuses to hit and damage, except for DF's, which aren't helped by the change at all and thus should keep their bonuses, and HA's, which might keep +2 to hit and +2 to damage. This would still strengthen all ego weapons except DF's significantly. We might compensate for such a change by removing the 3/2 multiplier for the chance of ego weapons, but we have still given a great reward to the player who finds a HA. The only sensible alternative I can see is to leave the old system for calculating damage, and to compute the added damage bonus with my function, then multiply for ego weapons and critical hits, and then add in the added damage bonus. >Also, your patch makes it much harder for people to figure out how two >weapons compare, because the damage formula is now more complicated, >and can not be easily calculated from the info available on screen. >Fixing the damage shown by the 'C' command would help, that should be easy. The damage should probably be displayed as Damage Bonus: +8(+12) with the +8 the sum of all your bonuses, and the +12 the rounded-off bonus as it applies to the average damage of your current weapon (or to 1d1 if you have no weapon wielded). >Or maybe use a simpler formula, for example a +1 weapons does 10% more >damage than normal (minimum of 1 extra damage point), and a +10 weapon >does twice normal damage, although this is probably far too much of a >difference between light and heavy weapons. I thought of this before, and rejected it because this had too great an effect on daggers. That's why I included the 2-point offset, so that a +9 weapon doubles the quantity (damage+2). David Grabiner, grabiner@zariski.harvard.edu "We are sorry, but the number you have dialed is imaginary." "Please rotate your phone 90 degrees and try again." Disclaimer: I speak for no one and no one speaks for me... moria-5.6.debian.1/misc/shading0000644000175000017500000002127005613574235014472 0ustar pjbpjbFrom ucbvax!tut.cis.ohio-state.edu!mailrus!uflorida!gatech!ncsuvx!ecemwl!jnh Status: RO Article 1484 of rec.games.programmer: Path: ucbvax!tut.cis.ohio-state.edu!mailrus!uflorida!gatech!ncsuvx!ecemwl!jnh >From: jnh@ecemwl.ncsu.edu (Joseph N. Hall) Newsgroups: rec.games.programmer Subject: Shading and line-of-sight calculation _en_masse_... Keywords: very very fast Message-ID: <4036@ncsuvx.ncsu.edu> Date: 25 Sep 89 17:10:09 GMT Sender: news@ncsuvx.ncsu.edu Reply-To: jnh@ecemwl.UUCP (Joseph N. Hall) Organization: North Carolina State University Lines: 192 Here is a rough presentation of the technique for calculating shading and visibility that I had mentioned earlier. ... (summary) A Fast Algorithm for Calculating Shading and Visibility in a Two-Dimensional Field By Joseph Hall Applications Programmer, North Carolina State University This document copyright 1989 by Joseph Hall. It may be reproduced in entirety for distribution for any purpose, so long as no fee whatsoever is charged for its distribution and no attempt is made to restrict its distribution. No other use is allowed without permission from the author. Permission from the author must be obtained if a substantial portion of this document is to be included in another copyrighted work. As the author of this document, I hereby release the ALGORITHMS described herein into the public domain. This release does not apply to the actual text of this document. --- Interactive terminal-based "rogue-like" games such as Hack, Moria, Omega, and, of course, the original Rogue, feature a player character traveling through a maze. The maze usually comprises several levels and is usually laid out on a grid of squares or "tiles." Each tile contains one of several distinct features, e.g., a piece of wall, floor, door, etc., and may also contain objects and/or creatures, if it is not solid. Hack and Rogue handle lighting and visibility quite simply. All corridors and walls are "visible" once they have been seen. Rooms are square and are either "lit" or "dark." A player carrying a lamp can see with a radius of 1 tile if he is in a corridor (which is always dark) or in a dark room. A player cannot see the occupants of a room until he steps into that room. These conditions eliminate the possible complexity of line-of-sight and shading computations, but detract somewhat from the "realism" of the game. Moria, on the other hand, allows for line-of-sight considerations. A player can see whatever is standing or resting on a tile is it is both lit and can be seen from his current location, i.e., if there are no "solid" tiles, such as walls or closed doors, intervening. Thus a player can see some of the contents of a room as he approaches its entrance, and more as he gets closer. Moria does not, however, allow for lights of radius greater than one tile, and only the player is allowed to carry a light. Again, all rooms are either lit or not lit, and corridors are dark, although certain player actions can permanently light portions of corridors and permanently light or darken portions of rooms. One can see the desirability of a more complex scheme, where the player is allowed a lamp of variable radius, other creatures can carry lamps, and rooms are lit by lamps with finite radius. Such a scheme is not trivial to implement, at least from the standpoint of the bookkeeping required, but the greatest difficulty is the amount of calculation required, which can easily take long enough on a microcomputer to remove the interactive feel of the game. Consider: Whenever the player moves, and thus his viewpoint changes, the visibility of the entire area surrounding him must be recalculated. This area will be either the visible area on the screen or the portion of it within a limited "sight radius" of the player. A sight radius of at least 25 tiles is desirable, and this could entail calculations for pi * 25 * 25 tiles, or about 2000 tiles. Additionally, whenever a light source moves (when carried by the player or by another creature), the lighting status of the area within the effective radius of the light source must be recalculated. Although a radius of 1-5 tiles is probably optimum for players and other creatures, there may be a number of these light sources on screen at the same time, and larger radii also have some application. Finally, considerable recalculation is required whenever the solidity of a visible tile changes, e.g., when a door opens or closes. The obvious approach to all of the above situations is to calculate both visibility and lighting status on a tile-by-tile basis using an ordinary "line-of-sight" routine. That is, for each light source on screen, calculate whether it lights a tile within its radius by seeing whether a line of sight exists between it and the tile; similarly, once the lighting status of all tiles on screen is known, calculate whether the player can see them by checking the line of sight from the player to each of the surrounding tiles. The difficulty here is that the line-of-sight routine must check each of the tiles intervening between the player/light source and destination. This makes the calculations described above roughly O(n^3), which is generally unsuitable. A previous posting on USENET suggested using "rays" emanating from the player or light source, one ray to each screen border tile or each tile of limiting circumference. The algorithm involves checking the solidity of tiles along each ray, beginning at the player or light source, and marking them visible until a solid object is encountered. While this is fast and efficient, it is incorrect. To wit: . | . | | . . | . . | . | . . . | . . . * * * * . . . @ . x . | @ . x * * @ . x * * @ . . . . @ . . (1) (2) (3) (4) (5) Here, @ is the center of a light source, x is a solid object, '*' represents a shaded tile, '.' is a lit tile, and '|' is a boundary. (1) shows the system without shading. (2) is the correct shading. (3) is the shading generated by the above algorithm. (4) and (5) are the lines of sight to the border that cause the incorrect shading to be generated. The correct shading will be generated only for the border tiles, and there will be some inaccuracies in the remaining shading. The author has, however, found an efficient technique that relies on tables of pre-calculated, rasterized shading. Consider this situation: . . . * . . . . . . * * . . . . . . . . * * * * . 3 . . . . . . . . * * . 3 * . . . 2 . . . . . . . . . 2 * * . . . . . @ . . 1 . . @ . . 1 * * @ . . . . . @ . . . . . (6) (7) (8) (9) '1,' '2,' and '3' represent solid objects. (7), (8) and (9) are the shading generated by the individual objects. The total shading can be generated by overlaying (7), (8) and (9): * * * * * * . 3 * * . . 2 * * @ . . 1 * * (10) Thus the problem of calculating shading for an area can be reduced to one of "summing" the shadows that its individual tiles create. This procedure is straightforward and won't be detailed in this short report. HOW TO STORE the pre-calculated shadows is a matter to consider, however. One might expect a full set of shadows, say, out to a radius of 32, to occupy an inordinate amount of space, or, if tightly compressed, to present problems in retrieval. But this turns out to be not nearly so bad. Symmetry considerations, first, reduce the number of shadows that must be stored by a factor of 8, since only one "octant" (45-degree slice), as shown above, need be calculated. The shadows can be stored as a series of "rasters," using the following representation for each shadow: byte 1 # of rasters in this shadow 2 #1 start 3 #1 end 4 #2 start 5 #2 end ... (7), (8) and (9) can be translated as follows: (7) 1 4-5 (8) 3 4-5 4-5 5-5 (9) 4 4-4 3-5 4-5 5-5 The full set of radius-32 shadows can, in fact, be stored in a readily- accessible table of LESS THAN 9000 BYTES. ... I have written a prototype that uses this shading technique. Missing certain optimizations in its current version, it still calculates a 32 x 32 area in a relatively-constant 50 milliseconds on an 8MHz 68000. The most efficient conventional LOS-based version that I have been able to write takes about 800 milliseconds. (!) I am working on a cleaner version of the prototype and table generator and will present them and a detailed report later (a couple of weeks?) in rec.games.programmer. v v sssss|| joseph hall || 4116 Brewster Drive v v s s || jnh@ecemwl.ncsu.edu (Internet) || Raleigh, NC 27606 v sss || SP Software/CAD Tool Developer, Mac Hacker and Keyboardist -----------|| Disclaimer: NCSU may not share my views, but is welcome to. moria-5.6.debian.1/misc/funckeys.c0000644000175000017500000000614105613574235015125 0ustar pjbpjb/* call e_inkey() in dungeon.c instead of inkey() */ int keypadon; /* e_inkey * This inkey processes function keys also (using map_keypad) */ /* Gets single character from keyboard and returns a character. If the key * pressed is a function key, it processes the key without waiting on the * escape. At this time it processes function keys by using map_keypad and * needs funckeys.h. If you don't want ANY escape processing, use inkey(). * If you are using this function, Escape will need to be pressed twice to get * an escape. */ e_inkey(ch) char *ch; { put_qio(); /* Dump IO buffer */ if (!keypadon) { *ch = getch(); return; } if ((*ch = getch()) != ESC) return; /* we now have an escape, if a [ does not follow it, send back a null */ if ((*ch = getch()) != FCHAR ) { if (*ch == ESC) return; *ch = INPUT_ERROR; return; } map_keypad(ch); } /* map_keypad is sun specific still. It should not be hard to change it for * any keypad. It needs funckeys.h to work and is only called from e_inkey(). * This seems to be too slow, and we are getting some processing errors that * look like short teleportation. */ map_keypad(ch) char *ch; { int c; int key, rawkey, n; char side; #if SUN switch (c = getch()) { case 'A': side = 'r'; key = 8; break; case 'B': side = 'r'; key = 14; break; case 'C': side = 'r'; key = 12; break; case 'D': side = 'r'; key = 10; break; default: rawkey = c - '0'; for (n = 0; c = getch(), n < 3; n++) { if (c == 'z') break; else if (c < '0' || c > '9') { *ch = INPUT_ERROR; return; } else rawkey = rawkey * 10 + c - '0'; } if (c != 'z') { *ch = INPUT_ERROR; return; } else if (rawkey >= 208 && rawkey <= 222) { side = 'r'; key = rawkey - 207; } else if (rawkey >= 192 && rawkey <= 201) { side = 'l'; key = rawkey - 191; } else if (rawkey >= 224 && rawkey <= 232) { side = 'f'; key = rawkey - 223; } else { *ch = INPUT_ERROR; return; } break; } if (side == 'r') *ch = rkeys[key]; else if (side == 'l') *ch = lkeys[key]; else if (side == 'f') *ch = fkeys[key]; else *ch = INPUT_ERROR; #endif } /* Prompts (optional) and returns False if ESC is the input character. escp * is a boolean option that allows you to decide if you want function key * processing or not. * * If the prompt is NULL or empty, nothing is printed and nothing is erase. */ get_com(prompt, command, escp) char *prompt; char *command; int escp; { int com_val; int res; int do_erase; if ((prompt != NULL) && (strlen(prompt) > 0)) { oprint(prompt); do_erase = TRUE; } else do_erase = FALSE; if (escp) inkey(command); else e_inkey(command); com_val = *command; switch (com_val) { case ESC: res = FALSE; break; default: res = TRUE; break; } if (do_erase == TRUE) erase_line(msg_line, msg_line); return (res); } moria-5.6.debian.1/files/0000755000175000017500000000000011074757450013277 5ustar pjbpjbmoria-5.6.debian.1/files/welcome.hlp0000644000175000017500000000064705613574141015442 0ustar pjbpjb Welcome to Moria! Your first task is to generate a character. You must specify a sex, a race and a class. Anytime before you have made these specifications, you can interrupt with control-C. You can also specify the race as often as you like by entering '%' to the class request. This will also regenerate your attributes. If this is your first time playing, you may want to read the manual first. moria-5.6.debian.1/files/COPYING0000644000175000017500000010451411057125325014326 0ustar pjbpjb GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . moria-5.6.debian.1/files/version.hlp0000644000175000017500000000407011057125455015465 0ustar pjbpjb VMS Moria Version 4.8 Version 0.1 : 03/25/83 Version 1.0 : 05/01/84 Version 2.0 : 07/10/84 Version 3.0 : 11/20/84 Version 4.0 : 01/20/85 Modules : V1.0 Dungeon Generator - RAK Character Generator - RAK & JWT Moria Module - RAK Miscellaneous - RAK & JWT V2.0 Town Level & Misc - RAK V3.0 Internal Help & Misc - RAK V4.0 Source Release Version - RAK Robert Alan Koeneke Jimmey Wayne Todd Jr. Student/University of Oklahoma Student/University of Oklahoma Umoria Version 5.5 (formerly UNIX Moria) Version 4.83 : 5/14/87 Version 4.85 : 10/26/87 Version 4.87 : 5/27/88 Version 5.0 : 11/2/89 Version 5.2 : 5/9/90 Version 5.3 : 3/25/91 Version 5.4 : 10/12/91 Version 5.5 : 8/12/92 David J. Grabiner, grabiner@alumni.princeton.edu James E. Wilson, Cygnus Support wilson@kithrup.com Other contributors: D. G. Kneller - MSDOS Moria port, reduced map display, 16 bit integers Christopher J. Stuart - recall, options, inventory, running code, etc. Curtis McCauley - Macintosh Moria port for MPW C Stephen A. Jacobs - Atari ST Moria port for MW C Other contributors: William Setzer - object naming code Dan Bernstein - UNIX hangup signal fix, many bug fixes Corey Gehman - Amiga Moria port Ralph Waters - VMS support code, IBM-PC Turbo C bug fixes Johsua Delahunty - VMS support code Todd Pierzina - VMS support code Joseph Hall - line of sight code, monster compiler Eric Vaitl - PC-Curses replacement for Turbo C Scott Kolodzieski - Atari ST port for Gnu C Hildo Biersma - Atari ST port for Turbo C Ben Schreiber - Macintosh port for Think C Copyright (c) 1989-94 James E. Wilson, Robert A. Keoneke This software may be copied and distributed for educational, research, and not for profit purposes provided that this copyright and statement are included in all such copies. Umoria Version 5.5, patch level 1 moria-5.6.debian.1/files/scores0000644000175000017500000000011411020652656014505 0ustar pjbpjb////&Kp8ËÈÂÂÈÈÈÉÉ„„…ñ”ç““³“³“³““““““ãæ¦¦¦¦¦b¦¥ì‚ö“á“æ–â‹å‚‚ªNK #Ç‚‚‚‚‚moria-5.6.debian.1/files/news0000644000175000017500000000162011057125017014162 0ustar pjbpjb ********************* ** Umoria 5.6 ** ********************* Copyright (c) 1985 Robert Alan Koeneke Copyright (c) 1989-94 James E. Wilson Programmers : Robert Alan Koeneke / University of Oklahoma Jimmey Wayne Todd / University of Oklahoma UNIX Port : James E. Wilson / Cygnus Support Versions 5.5-5.6 : David J. Grabiner Umoria 5.6 is free software, and you are welcome to distribute it under certain conditions; for details, type control-V after starting a character. Umoria 5.6 comes with ABSOLUTELY NO WARRANTY; for details, type control-V and view sections 15-17 of the License. Please send bug reports to grabiner@alumni.princeton.edu or to the USENET newsgroup rec.games.roguelike.moria. Moria 4.8x users, please read doc/FEATURES.NEW for information on changes. moria-5.6.debian.1/files/hours0000644000175000017500000000053605613574141014362 0ustar pjbpjb Moria operating hours are: | AM | PM | 1 111 111 2123456789012123456789012 SUN:XXXXXXXXXXXXXXXXXXXXXXXX MON:XXXXXXXXXXXXXXXXXXXXXXXX TUE:XXXXXXXXXXXXXXXXXXXXXXXX WED:XXXXXXXXXXXXXXXXXXXXXXXX THU:XXXXXXXXXXXXXXXXXXXXXXXX FRI:XXXXXXXXXXXXXXXXXXXXXXXX SAT:XXXXXXXXXXXXXXXXXXXXXXXX (X=Open; .=Closed) moria-5.6.debian.1/files/rwizcmds.hlp0000644000175000017500000000057005613574142015645 0ustar pjbpjb* - Wizard light. : - Map area. \ - Wizard Help. ^A - Remove Curse and Cure all maladies. ^D - Down/Up n levels. ^E - Change character. ^F - Delete monsters. ^G - Allocate treasures. ^I - Identify. ^O - Print random objects sample. ^T - Teleport player. ^W - Wizard password on/off. @ - Create any object *CAN CAUSE FATAL ERROR* + - Gain experience. & - Summon monster. moria-5.6.debian.1/files/origcmds.hlp0000644000175000017500000000602211057125016015577 0ustar pjbpjbCommand summary: (@ is optional count, ~ is direction, ^R redraws, ESC aborts) a Aim and fire a wand | @ B ~ Bash item or monster b Browse a book | C Character description c ~ Close a door | @ D ~ Disarm a trap/chest d Drop an item | E Eat some food e Equipment list | F Fill lamp with oil f Fire/Throw an item | G Gain new magic spells i Inventory list | L Locate with map @ j ~ Jam a door with spike | M Map shown reduced size l ~ Look given direction | @ R Rest (Count or *=restore) m Magic spell casting | S Search Mode @ o ~ Open a door/chest | @ T ~ Tunnel in a direction p Pray | V View scoreboard q Quaff a potion | = Set options r Read a scroll | ? Type this page @ s Search for traps or doors | { Inscribe an object t Take off an item | @ - Move without pickup u Use a staff | . ~ Run in direction v Version info and credits | / Identify a character w Wear/Wield an item | CTRL-K Quit the game x Exchange weapon | @ CTRL-P Repeat the last message < Go up an up-staircase | CTRL-X Save character and quit > Go down a down-staircase | @ ~ for movement Directions: 7 8 9 4 5 6 [5 is stay] 1 2 3 To give a count to a command, type a '#', followed by the digits. A count of 0 defaults to a count of 99. Counts only work with some commands, and will be terminated by the same things that end a rest or a run. In particular, typing any character during the execution of a counted command will terminate the command. To count a movement command, hit space after the number, and you will be prompted for the command, which may be a digit. Counted searches or tunnels will terminate on success, or if you are attacked. A count with control-P will specify the number of previous messages to display. Control-R will redraw the screen whenever it is input, not only at command level. Control commands may be entered with a single key stroke, or with two key strokes by typing ^ and then a letter. Type ESCAPE to abort the look command at any point. Some commands will prompt for a spell, or an inventory item. Selection is by an alphabetic character - entering a capital causes a desription to be printed, and the selection may be aborted. Typing `R*' will make you rest until both your mana and your hp reach their maximum values. Umoria 5.6 is free software, and you are welcome to distribute it under certain conditions; for details, type control-V. Umoria 5.6 comes with ABSOLUTELY NO WARRANTY; for details, type control-V and view sections 15-17 of the License. moria-5.6.debian.1/files/owizcmds.hlp0000644000175000017500000000057005613574141015641 0ustar pjbpjb: - Map area. ^A - Remove Curse and Cure all maladies. ^B - Print random objects sample. ^D - Down/Up n levels. ^E - Change character. ^F - Delete monsters. ^G - Allocate treasures. ^H - Wizard Help. ^I - Identify. ^J - Gain experience. ^L - Wizard light. ^T - Teleport player. ^U - Summon monster. ^W - Wizard password on/off. @ - Create any object *CAN CAUSE FATAL ERROR* moria-5.6.debian.1/files/roglcmds.hlp0000644000175000017500000000632711057125014015610 0ustar pjbpjbCommand summary: (@ is optional count, ~ is direction, ^R redraws, ESC aborts) c ~ Close a door. | C Character player description. d Drop an item. | @ D ~ Disarm a trap/chest. e Equipment list. | E Eat some food. @ f ~ Force (bash) item or mons.| F Fill lamp with oil. i Inventory list. | G Gain new magic spells. m magic spell casting. | M Map, show reduced size. @ o ~ Open a door/chest. | P Peruse a book. p Pray. | Q Quit the game. q Quaff a potion. | @ R Rest (Count or *=restore). r Read a scroll. | @ S ~ Spike a door. @ s Search for traps or doors.| T Take off an item. t Throw an item. | V View scores. v Version info | W Where: locate self. w Wear/Wield an item. | X Exchange weapon. x ~ Examine surroundings | Z Zap a staff. z Zap a wand. | # Search Mode. = Set options. | < Go up an up-staircase. / Identify a character. | > Go down a down-staircase. @ CTRL-P Previous message review | { Inscribe an object. @ - ~ Move without pickup. | ? Type this page. @ CTRL ~ Tunnel in a direction. | CTRL-X Save character and exit. @ SHIFT ~ Run in direction. | @ ~ For movement. Directions: y k u h . l [. is stay] b j n To give a count to a command, type the number in digits, then the command. A count of 0 defaults to a count of 99. Counts only work with some commands, and will be terminated by the same things that end a rest or a run. In particular, typing any character during the execution of a counted command will terminate the command. Counted searches or tunnels will terminate on success, or if you are attacked. A count with control-P will specify the number of previous messages to display. Control-R will redraw the screen whenever it is input, not only at command level. Control commands may be entered with a single key stroke, or with two key strokes by typing ^ and then a letter. Type ESCAPE to abort the look command at any point. Some commands will prompt for a spell, or an inventory item. Selection is by an alphabetic character - entering a capital causes a desription to be printed, and the selection may be aborted. Typing `R*' will make you rest until both your mana and your hp reach their maximum values. Using repeat counts with the tunnel left command does not work well, because tunnel left is the backspace character, and will delete the number you have just typed in. To avoid this, you can either enter ^H as two characters (^ and then H), or you can type ' ' (i.e. the space character) after the number at which point you will get a command prompt and backspace will work correctly. Umoria 5.6 is free software, and you are welcome to distribute it under certain conditions; for details, type control-V. Umoria 5.6 comes with ABSOLUTELY NO WARRANTY; for details, type control-V and view sections 15-17 of the License. moria-5.6.debian.1/util/0000755000175000017500000000000005613574160013147 5ustar pjbpjbmoria-5.6.debian.1/util/map.c0000644000175000017500000000571505613574156014105 0ustar pjbpjb/* this used to be in files.c, this is not a working program */ /* Output dungeon section sizes */ #define OUTPAGE_HEIGHT 44 /* 44 lines of dungeon per section */ #define OUTPAGE_WIDTH 99 /* 100 columns of dungeon per section */ /* deleted in favor of improved Map and Where commands */ /* Prints dungeon map to external file -RAK- */ print_map() { register int i, j, m, n; register k, l; register i7, i8; char dun_line[MAX_WIDTH+1]; char *dun_ptr; static vtype filename1 = "MORIAMAP.DAT"; vtype filename2; char tmp_str[80]; FILE *file1; static int page_width = OUTPAGE_WIDTH; static int page_height = OUTPAGE_HEIGHT; /* this allows us to strcat each character in the inner loop, instead of using the expensive sprintf */ (void) sprintf (tmp_str, "File name [%s]: ", filename1); prt(tmp_str, 0, 0); if (get_string(filename2, 0, strlen(tmp_str), 64)) { if (strlen(filename2) > 0) (void) strcpy(filename1, filename2); if ((file1 = fopen(filename1, "w")) == NULL) { (void) sprintf(dun_line, "Cannot open file %s", filename1); prt(dun_line, 0, 0); return; } (void) sprintf(tmp_str, "section width (default = %d char):", page_width); prt(tmp_str, 0, 0); (void) get_string(tmp_str, 0, strlen(tmp_str), 10); page_width = atoi(tmp_str); if (page_width < 10) page_width = 10; (void) sprintf(tmp_str, "section height (default = %d lines):", page_height); prt(tmp_str, 0, 0); (void) get_string(tmp_str, 0, strlen(tmp_str), 10); page_height = atoi(tmp_str); if (page_height < 10) page_height = 10; prt("Writing Moria Dungeon Map...", 0, 0); put_qio(); i = 0; i7 = 0; do { j = 0; k = i + page_height - 1; if (k >= cur_height) k = cur_height - 1; i7++; i8 = 0; do { l = j + page_width - 1; if (l >= cur_width) l = cur_width - 1; i8++; (void) fprintf(file1, "%c\n", CTRL('L')); (void) fprintf(file1, "Section[%d,%d]; ", i7, i8); (void) fprintf(file1, "Depth : %d (feet)\n\n ", (dun_level * 50)); for (m = j; m <= l; m++) { n = (m / 100); (void) fprintf(file1, "%d", n); } (void) fputs("\n ", file1); for (m = j; m <= l; m++) { n = (m / 10) - (m / 100) * 10; (void) fprintf(file1, "%d", n); } (void) fputs("\n ", file1); for (m = j; m <= l; m++) { n = m - (m / 10) * 10; (void) fprintf(file1, "%d", n); } (void) fprintf(file1, "\n"); for (m = i; m <= k; m++) { (void) sprintf(dun_line, "%2d ", m); dun_ptr = &dun_line[3]; for (n = j; n <= l; n++) *dun_ptr++ = loc_symbol(m, n); *dun_ptr++ = '\n'; *dun_ptr++ = '\0'; (void) fputs(dun_line, file1); } j += page_width; } while (j < cur_width); i += page_height; } while (i < cur_height); (void) fclose(file1); prt("Completed.", 0, 0); } } moria-5.6.debian.1/util/mcheck.inf0000644000175000017500000001216505613574156015111 0ustar pjbpjb Goal: write a little program that will check the monster file for consistency, since I am tired of doing this manually; the comments below detail everything that the program will verify **************** Creature classification scheme dragon: d, D never invisible, can't open doors, never phase, never eats others, never pick up objects, never multiply, carry objects/gold, breath weapons, cast spells, hurt by slay dragon, hurt by slay evil, can be slept, seen by infravision, young/mature 20% random movement humanoid: h, H, k, n, o, p, P, T, U, y, Y can open doors, never eats others, all that carry treasure pick up obj, never multiply, h/U/Y and some people don't carry treasure, some cast spells, no breath weapons, all except some humans evil, hurt by slay evil, can be slept, seen by infravision, never random movement (except 0 level humans which are all 20% random) undead: G, L, M, s, V, W, Z only G invisible, all except s/Z open doors, only G/W phase, never eats others, only G picks up objects, never multiply, only s/Z do not carry objects/gold, some cast spells, no breath weapons, all evil except s/Z, hurt by slay evil, hurt by slay undead, can't be slept, never seen by infravision, G very random movement, W 20% random movement, others never random movement animal: a, A, b, c, f, F, j, K, l, r, R, S, t, w only one of a/c invisible, can't open doors, never phase, only A eats others, never pick up objects, only a/b/F/l/r/w multiply, never carry objects or gold, never cast spells, some breath weapons, not evil, hurt by slay animal, can be slept, mammals seen by infravision, most have 20% random movement demons: B, p(Evil Iggy), q always invisible, only B can phase, only B eats others, always pick up objects, never multiply, carry objects/gold, cast spells, only B breath weapon, all evil, hurt by slay evil, can not be slept, not seen by infravision, never random movement quylthulg: Q in a class by itself, almost exactly the same as demon except not evil and does not carry objects/gold, should be in class other other: C, e, E, g, i, J, m, O, X, $, ',' some can be invisible, never open doors, only X phase, only C/E/i/O eats others, only C/E/i/O pick up objects, only O/',' multiply, only C/i/O carry objects/gold, $ carries only gold, no breath weapons, not evil (all brainless creatures), not hurt by any special weapon, can't be slept, never seen with infravision, brainless creatures, some drain mana/exp/etc., fire/air elementals (includes invisible stalker) move quickly, golems are animated and should never move randomly, the rest never move or move slowly/randomly if they do Miscellaneous overriding factors: if invisible, not seen by infravision if invisible, not hurt by blue light if frost attack, not seen by infravion if frost attack, not hurt by cold if frost attack, hurt by fire if fire attack, seen by infravision if fire attack, not hurt by fire if fire attack, hurt by frost if fire&frost attack, not hurt by fire nor cold, infravision depends on class if acid attack, not hurt by acid if poison/corrosion gas attack, not hurt by poison if lightning attack, not hurt by blue light if lungless, can not breathe/spit damage if invisible can not gaze damage if stone-to-mud hurt, not cold/fire hurt if not move and brainless, in general, not carry objects/gold if move and brainless, in general, carry objects/gold only if pick up objects Possible changes: examine vulnerability list for errors, changes, things that don't make sense, additions, etc... need to classify lungless creatures here somewhere creatures without limbs should not claw for damage creatures without mouths should not bite for damage Special vulnerabilities for each class: a: none A: cold, fire b: fire, poison, blue light B: none c: none C: fire d: none D: none e: blue light E: cold(fire), fire(water), stone-to-mud(earth), none (stalker,air) f: acid, fire F: cold, fire, poison g: cold, fire, acid, blue light(flesh) g: stone-to-mud (clay/stone) g: acid (iron) G: none h: cold, fire H: cold, fire i: none I: {no monster} j: cold, fire J: fire, acid, blue light k: cold, fire K: none l: cold, fire, acid, poison, blue light L: none m: fire, acid M: fire n: fire, poison, acid N: {no monster} o: cold, fire O: fire, acid p: fire, cold P: stone-to-mud (stone) P: cold, fire (all except stone) q: none Q: none r: cold, fire, poison R: cold, fire, acid s: none S: none t: fire T: fire u: {no monster} U: fire, blue light v: {no monster} V: fire, blue light w: cold, fire, acid, blue light W: fire, blue light x: {no monster} X: stone-to-mud y: cold, fire Y: fire z: fire Z: {no monster} $: none ,: fire, acid Obvious errors in monster.c file: Here is a list of errors in the monster.c file, assuming that the above classification scheme is used. I have not examined the entire list. squint-eyed rogue should move 20% randomly spirit troll should not be type 'T', since this is not an undead type, should carry objects depending on which type it is changed to if make zombie must remove phase ability if make ghost must make invisible creeping coins: touch for normal damage, bite for poison damage depends: pick_up_obj, movement moria-5.6.debian.1/util/README0000644000175000017500000000201405613574156014031 0ustar pjbpjbmap.c is obsolete `print map to file' code from 4.87, superceded by the reduced map display, and the improved Where/Locate code mc is a monster compiler by Joseph N Hall. It would be nice if this was used to generate the monster.c file. This would be more maintainable that the current method. mcheck.inf: my and David J. Grabiner's ideas on monster consistency, and checks that should be added to the monster compiler mergemem: code from Eric W. Bazin to merge monster memory from different savefiles monster.cng: a list of some of the changes to the monster.c file, is this still needed? printit.c: some code which will pretty print item/monster descriptions, written by Carl Hommel scores: two standalone programs for dealing with scorefiles, one to print scorefiles, and another to delete a single record from a scorefile showmon.c: obsolete code from 4.87 for printing the monster dictionary, superceded by the monster memories weapons: a program which roughly indicates which weapons are best, written by Wayne Schlitt moria-5.6.debian.1/util/scores/0000755000175000017500000000000011074757477014461 5ustar pjbpjbmoria-5.6.debian.1/util/scores/print.c0000644000175000017500000001172311074756221015747 0ustar pjbpjb/* util/scores/print.c: standalone program to print score file Copyright (c) 1991 James E. Wilson This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include #include "../../source/config.h" #include "../../source/constant.h" #include "../../source/types.h" #include "../../source/externs.h" #if defined(USG) || defined(VMS) #ifndef L_SET #define L_SET 0 #endif #ifndef L_INCR #define L_INCR 1 #endif #endif #undef fopen #ifndef USG /* only needed for Berkeley UNIX */ #include #include #include #endif extern race_type race[MAX_RACES]; extern class_type class[MAX_CLASS]; FILE *highscore_fp; FILE *fileptr; int8u xor_byte; void set_fileptr(); main(argc, argv) int argc; char *argv[]; { register int i, rank; high_scores score; char string[100]; int8u version_maj, version_min, patch_level; int16 player_uid; if (argc != 2) { printf ("Usage: print scorefile\n"); exit (-2); } if ((highscore_fp = fopen (argv[1], "r")) == NULL) { printf ("Error opening score file \"%s\"\n", MORIA_TOP); exit (-1); } #ifdef MSDOS (void) setmode (fileno(highscore_fp), O_BINARY); #endif #ifndef BSD4_3 (void) fseek(highscore_fp, (long)0, L_SET); #else (void) fseek(highscore_fp, (off_t)0, L_SET); #endif /* Read version numbers from the score file, and check for validity. */ version_maj = getc (highscore_fp); version_min = getc (highscore_fp); patch_level = getc (highscore_fp); /* Support score files from 5.2.2 to present. */ if (feof (highscore_fp)) { printf ("The scorefile is empty.\n"); exit (-1); } else if ((version_maj != CUR_VERSION_MAJ) || (version_min > CUR_VERSION_MIN) || (version_min == CUR_VERSION_MIN && patch_level > PATCH_LEVEL) || (version_min == 2 && patch_level < 2) || (version_min < 2)) { printf("Sorry. This scorefile is from a different version of umoria.\n"); exit (-1); } #ifdef unix player_uid = getuid (); #else #ifdef VMS player_uid = (getgid()*1000) + getuid(); #else player_uid = 0; #endif #endif /* set the static fileptr in save.c to the highscore file pointer */ set_fileptr(highscore_fp); rank = 1; rd_highscore(&score); printf("Rank Points Name Sex Race Class Lvl Killed By\n"); while (!feof(highscore_fp)) { i = 1; /* Put twenty scores on each page, on lines 2 through 21. */ while (!feof(highscore_fp) && i < 21) { (void) sprintf(string, "%-4d%8ld %-19.19s %c %-10.10s %-7.7s%3d %-22.22s\n", rank, score.points, score.name, score.sex, race[score.race].trace, class[score.class].title, score.lev, score.died_from); printf (string, ++i); rank++; rd_highscore(&score); } } /* Success. */ exit (0); } static void rd_byte(ptr) int8u *ptr; { int8u c; c = getc(fileptr) & 0xFF; *ptr = c ^ xor_byte; xor_byte = c; } static void rd_short(ptr) int16u *ptr; { int8u c; int16u s; c = (getc(fileptr) & 0xFF); s = c ^ xor_byte; xor_byte = (getc(fileptr) & 0xFF); s |= (int16u)(c ^ xor_byte) << 8; *ptr = s; } static void rd_long(ptr) int32u *ptr; { register int32u l; register int8u c; c = (getc(fileptr) & 0xFF); l = c ^ xor_byte; xor_byte = (getc(fileptr) & 0xFF); l |= (int32u)(c ^ xor_byte) << 8; c = (getc(fileptr) & 0xFF); l |= (int32u)(c ^ xor_byte) << 16; xor_byte = (getc(fileptr) & 0xFF); l |= (int32u)(c ^ xor_byte) << 24; *ptr = l; } static void rd_bytes(ch_ptr, count) int8u *ch_ptr; register int count; { register int i; register int8u *ptr; register int8u c; ptr = ch_ptr; for (i = 0; i < count; i++) { c = (getc(fileptr) & 0xFF); *ptr++ = c ^ xor_byte; xor_byte = c; } } /* set the local fileptr to the scorefile fileptr */ void set_fileptr(file) FILE *file; { fileptr = file; } void rd_highscore(score) high_scores *score; { /* Read the encryption byte. */ rd_byte (&xor_byte); rd_long((int32u *)&score->points); rd_long((int32u *)&score->birth_date); rd_short((int16u *)&score->uid); rd_short((int16u *)&score->mhp); rd_short((int16u *)&score->chp); rd_byte(&score->dun_level); rd_byte(&score->lev); rd_byte(&score->max_dlv); rd_byte(&score->sex); rd_byte(&score->race); rd_byte(&score->class); rd_bytes((int8u *)score->name, PLAYER_NAME_SIZE); rd_bytes((int8u *)score->died_from, 25); } moria-5.6.debian.1/util/scores/Makefile0000644000175000017500000000033205613574157016111 0ustar pjbpjball: prscore delscore # Use the player.c from ../../source prscore: print.o player.o cc -o prscore print.o player.o delscore: delete.o cc -o delscore delete.o clean: rm delscore delete.o prscore print.o player.o moria-5.6.debian.1/util/scores/README0000644000175000017500000000345605613574160015335 0ustar pjbpjbThis directory contains two simple utilities for dealing with score files. The first, prscore, will simply print a list of every score in the given scorefile to standard output. The second, delscore, will send a copy of the scorefile to standard output, except that the nth entry will be deleted. If you wish to delete an entry from your scorefile, use them as follows. Run "prscore scorefile" to see every entry in the scorefile. Note the index (i.e. rank) of the entry you want to delete. Then run "delscore scorefile n > tmp.score" where 'n' is the number of the entry you want to delete. Then run "prscore tmp.score" to ensure that the scorefile is OK. You can then copy the tmp.score file over your current scorefile. Note: do not try to run "delscore scorefile n > scorefile". You will lose your scorefile if you do this. ERRORS: 1) This has not been well tested. It may not work for everyone. It probably won't compile on every machine that umoria currently supports without a few changes. 2) If people are playing umoria while you use these utilties to edit the scorefile, you may lose an entry when copying the new scorefile over the old. These utilities really should lock the scorefile, and then do their work inplace. Meanwhile, to be safe, only do this when no one is playing (you can use the hours file to force this), or else do this really really fast. 3) It includes parts of save.c to make compilation easier. This may cause this to fail if save.c is modified and these programs aren't. It really should be linked with save.o. 4) It should prompt for the output file name, and then verify that the output file and the input file are different, to prevent people from accidently destroying their scorefile. (Or, this can also be fixed by doing all work in place.) moria-5.6.debian.1/util/scores/delete.c0000644000175000017500000001442711074756221016061 0ustar pjbpjb/* util/scores/delete.c: standalone program to delete record from scorefile Copyright (c) 1991 James E. Wilson This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include #include "../../source/config.h" #include "../../source/constant.h" #include "../../source/types.h" #include "../../source/externs.h" #if defined(USG) || defined(VMS) #ifndef L_SET #define L_SET 0 #endif #ifndef L_INCR #define L_INCR 1 #endif #endif #undef fopen #ifndef USG /* only needed for Berkeley UNIX */ #include #include #include #endif extern race_type race[MAX_RACES]; extern class_type class[MAX_CLASS]; FILE *highscore_fp; FILE *fileptr; int8u xor_byte; void set_fileptr(); main(argc, argv) int argc; char *argv[]; { register int i, rank; high_scores score; int8u version_maj, version_min, patch_level; int delete_number; if (argc != 3) { printf ("Usage: delete scorefile index > newscore\n"); exit (-2); } if ((highscore_fp = fopen (argv[1], "r")) == NULL) { printf ("Error opening score file \"%s\"\n", MORIA_TOP); exit (-1); } if ((delete_number = atoi (argv[2])) <= 0) { printf ("Index must be a positive number.\n"); printf ("Usage: delete scorefile index\n"); exit (-2); } #ifdef MSDOS (void) setmode (fileno(highscore_fp), O_BINARY); #endif #ifndef BSD4_3 (void) fseek(highscore_fp, (long)0, L_SET); #else (void) fseek(highscore_fp, (off_t)0, L_SET); #endif /* Read version numbers from the score file, and check for validity. */ version_maj = getc (highscore_fp); version_min = getc (highscore_fp); patch_level = getc (highscore_fp); /* Support score files from 5.2.2 to present. */ if (feof (highscore_fp)) { printf ("The scorefile is empty.\n"); exit (-1); } else if ((version_maj != CUR_VERSION_MAJ) || (version_min > CUR_VERSION_MIN) || (version_min == CUR_VERSION_MIN && patch_level > PATCH_LEVEL) || (version_min == 2 && patch_level < 2) || (version_min < 2)) { printf("Sorry. This scorefile is from a different version of umoria.\n"); exit (-1); } (void) putc (version_maj, stdout); (void) putc (version_min, stdout); (void) putc (patch_level, stdout); /* set the static fileptr in save.c to the highscore file pointer */ set_fileptr(highscore_fp); rank = 1; rd_highscore(&score); while (!feof(highscore_fp)) { i = 1; /* Put twenty scores on each page, on lines 2 through 21. */ while (!feof(highscore_fp) && i < 21) { if (rank != delete_number) { set_fileptr (stdout); wr_highscore (&score); set_fileptr (highscore_fp); } rank++; rd_highscore(&score); } } /* Success. */ exit (0); } static void wr_byte(c) int8u c; { xor_byte ^= c; (void) putc((int)xor_byte, fileptr); } static void wr_short(s) int16u s; { xor_byte ^= (s & 0xFF); (void) putc((int)xor_byte, fileptr); xor_byte ^= ((s >> 8) & 0xFF); (void) putc((int)xor_byte, fileptr); } static void wr_long(l) register int32u l; { xor_byte ^= (l & 0xFF); (void) putc((int)xor_byte, fileptr); xor_byte ^= ((l >> 8) & 0xFF); (void) putc((int)xor_byte, fileptr); xor_byte ^= ((l >> 16) & 0xFF); (void) putc((int)xor_byte, fileptr); xor_byte ^= ((l >> 24) & 0xFF); (void) putc((int)xor_byte, fileptr); } static void wr_bytes(c, count) int8u *c; register int count; { register int i; register int8u *ptr; ptr = c; for (i = 0; i < count; i++) { xor_byte ^= *ptr++; (void) putc((int)xor_byte, fileptr); } } static void rd_byte(ptr) int8u *ptr; { int8u c; c = getc(fileptr) & 0xFF; *ptr = c ^ xor_byte; xor_byte = c; } static void rd_short(ptr) int16u *ptr; { int8u c; int16u s; c = (getc(fileptr) & 0xFF); s = c ^ xor_byte; xor_byte = (getc(fileptr) & 0xFF); s |= (int16u)(c ^ xor_byte) << 8; *ptr = s; } static void rd_long(ptr) int32u *ptr; { register int32u l; register int8u c; c = (getc(fileptr) & 0xFF); l = c ^ xor_byte; xor_byte = (getc(fileptr) & 0xFF); l |= (int32u)(c ^ xor_byte) << 8; c = (getc(fileptr) & 0xFF); l |= (int32u)(c ^ xor_byte) << 16; xor_byte = (getc(fileptr) & 0xFF); l |= (int32u)(c ^ xor_byte) << 24; *ptr = l; } static void rd_bytes(ch_ptr, count) int8u *ch_ptr; register int count; { register int i; register int8u *ptr; register int8u c; ptr = ch_ptr; for (i = 0; i < count; i++) { c = (getc(fileptr) & 0xFF); *ptr++ = c ^ xor_byte; xor_byte = c; } } /* set the local fileptr to the scorefile fileptr */ void set_fileptr(file) FILE *file; { fileptr = file; } void wr_highscore(score) high_scores *score; { /* Save the encryption byte for robustness. */ wr_byte(xor_byte); wr_long((int32u) score->points); wr_long((int32u) score->birth_date); wr_short((int16u) score->uid); wr_short((int16u) score->mhp); wr_short((int16u) score->chp); wr_byte(score->dun_level); wr_byte(score->lev); wr_byte(score->max_dlv); wr_byte(score->sex); wr_byte(score->race); wr_byte(score->class); wr_bytes((int8u *)score->name, PLAYER_NAME_SIZE); wr_bytes((int8u *)score->died_from, 25); } void rd_highscore(score) high_scores *score; { /* Read the encryption byte. */ rd_byte (&xor_byte); rd_long((int32u *)&score->points); rd_long((int32u *)&score->birth_date); rd_short((int16u *)&score->uid); rd_short((int16u *)&score->mhp); rd_short((int16u *)&score->chp); rd_byte(&score->dun_level); rd_byte(&score->lev); rd_byte(&score->max_dlv); rd_byte(&score->sex); rd_byte(&score->race); rd_byte(&score->class); rd_bytes((int8u *)score->name, PLAYER_NAME_SIZE); rd_bytes((int8u *)score->died_from, 25); } moria-5.6.debian.1/util/showmon.c0000644000175000017500000002663105613574156015022 0ustar pjbpjb/* this used to be in files.c, this is not a working program */ /* move to cheat.c file */ /* Prints a listing of monsters -RAK- */ print_monsters() { register int i; int j, xpos, attype, adesc, adice, asides, count; register FILE *file1; vtype out_val, filename1; char *attstr; register creature_type *c_ptr; register char *string; prt("File name: ", 0, 0); if (get_string(filename1, 0, 11, 64)) { if (strlen(filename1) == 0) (void) strcpy(filename1, "MORIAMON.DAT"); if ((file1 = fopen(filename1, "w")) != NULL) { prt("Writing Monster Dictionary...", 0, 0); put_qio(); for (i = 0; i < MAX_CREATURES; i++) { c_ptr = &c_list[i]; /* Begin writing to file */ (void) fprintf(file1, "------------------------------------"); (void) fprintf(file1, "--------\n"); (void) fprintf(file1, "%3d %-31s (%c)\n", i, c_ptr->name, c_ptr->cchar); (void) fprintf(file1, " Speed =%3d Level =%3d Exp =%6u\n", c_ptr->speed-10, c_ptr->level, c_ptr->mexp); (void) fprintf(file1, " AC =%3d Eye-sight =%3d HD =%6s\n", c_ptr->ac, c_ptr->aaf, c_ptr->hd); if (CM_WIN & c_ptr->cmove) (void) fprintf(file1, " Creature is a ***Win Creature***\n"); if (CM_EATS_OTHER) & c_ptr->cmove) (void) fprintf(file1, " Creature Eats/kills other creatures.\n"); if (CD_DRAGON & c_ptr->cdefense) (void) fprintf(file1, " Creature is a dragon.\n"); if (CD_ANIMAL & c_ptr->cdefense) (void) fprintf(file1, " Creature is an animal.\n"); if (CD_EVIL & c_ptr->cdefense) (void) fprintf(file1, " Creature is evil.\n"); if (CD_UNDEAD & c_ptr->cdefense) (void) fprintf(file1, " Creature is undead.\n"); if (CD_FROST & c_ptr->cdefense) (void) fprintf(file1, " Creature harmed by cold.\n"); if (CD_FIRE & c_ptr->cdefense) (void) fprintf(file1, " Creature harmed by fire.\n"); if (CD_POISON & c_ptr->cdefense) (void) fprintf(file1, " Creature harmed by poison.\n"); if (CD_ACID & c_ptr->cdefense) (void) fprintf(file1, " Creature harmed by acid.\n"); if (CD_LIGHT & c_ptr->cdefense) (void) fprintf(file1, " Creature harmed by blue light.\n"); if (CD_STONE & c_ptr->cdefense) (void) fprintf(file1, " Creature harmed by Stone-to-Mud.\n"); if (CD_NO_SLEEP & c_ptr->cdefense) (void) fprintf(file1, " Creature cannot be charmed or slept.\n"); if (CD_INFRA & c_ptr->cdefense) (void) fprintf(file1, " Creature seen with Infra-Vision.\n"); if (CD_MAX_HP & c_ptr->cdefense) (void) fprintf(file1, " Creature has MAX hit points.\n"); if (CM_INVISIBLE & c_ptr->cmove) (void) fprintf(file1, " Creature is invisible.\n"); if (CM_PICKS_UP & c_ptr->cmove) (void) fprintf(file1, " Creature picks up objects.\n"); if (CM_MULTIPLY & c_ptr->cmove) (void) fprintf(file1, " Creature multiplies.\n"); if (CM_CARRY_OBJ & c_ptr->cmove) (void) fprintf(file1, " Carries object(s).\n"); if (CM_CARRY_GOLD & c_ptr->cmove) (void) fprintf(file1, " Carries gold, gems, etc.\n"); if (CM_60_RANDOM & c_ptr->cmove) (void) fprintf(file1, " Has object/gold 60%% of time.\n"); if (CM_90_RANDOM & c_ptr->cmove) (void) fprintf(file1, " Has object/gold 90%% of time.\n"); if (CM_1D2_OBJ & c_ptr->cmove) (void) fprintf(file1, " Has 1d2 object(s)/gold.\n"); if (CM_2D2_OBJ & c_ptr->cmove) (void) fprintf(file1, " Has 2d2 object(s)/gold.\n"); if (CM_4D2_OBJ & c_ptr->cmove) (void) fprintf(file1, " Has 4d2 object(s)/gold.\n"); /* * Creature casts spells / Breathes Dragon * breath. */ if (c_ptr->spells != 0) { (void) fprintf(file1, " --Spells/Dragon Breath =\n"); (void) fprintf(file1, " Casts spells 1 out of %d turns.\n", (int)(CS_FREQ & c_ptr->spells)); if (CS_TEL_SHORT & c_ptr->spells) (void) fprintf(file1, " Can teleport short.\n"); if (CS_TEL_LONG & c_ptr->spells) (void) fprintf(file1, " Can teleport long.\n"); if (CS_TEL_TO & c_ptr->spells) (void) fprintf(file1, " Teleport player to itself.\n"); if (CS_LGHT_WND & c_ptr->spells) (void) fprintf(file1, " Cause light wounds.\n"); if (CS_SER_WND & c_ptr->spells) (void) fprintf(file1, " Cause serious wounds.\n"); if (CS_HOLD_PER & c_ptr->spells) (void) fprintf(file1, " Hold person.\n"); if (CS_BLIND & c_ptr->spells) (void) fprintf(file1, " Cause blindness.\n"); if (CS_CONFUSE & c_ptr->spells) (void) fprintf(file1, " Cause confusion.\n"); if (CS_FEAR & c_ptr->spells) (void) fprintf(file1, " Cause fear.\n"); if (CS_SUMMON_MON & c_ptr->spells) (void) fprintf(file1, " Summon a monster.\n"); if (CS_SUMMON_UND & c_ptr->spells) (void) fprintf(file1, " Summon an undead.\n"); if (CS_SLOW_PER & c_ptr->spells) (void) fprintf(file1, " Slow person.\n"); if (CS_DRAIN_MANA & c_ptr->spells) (void) fprintf(file1, " Drains mana for healing.\n"); if (0x00020000L & c_ptr->spells) (void) fprintf(file1, " **Unknown spell value**\n"); if (0x00040000L & c_ptr->spells) (void) fprintf(file1, " **Unknown spell value**\n"); if (CS_BR_LIGHT & c_ptr->spells) (void) fprintf(file1, " Breathes Lightning Dragon Breath.\n"); if (CS_BR_GAS & c_ptr->spells) (void) fprintf(file1, " Breathes Gas Dragon Breath.\n"); if (CS_BR_ACID & c_ptr->spells) (void) fprintf(file1, " Breathes Acid Dragon Breath.\n"); if (CS_BR_FROST & c_ptr->spells) (void) fprintf(file1, " Breathes Frost Dragon Breath.\n"); if (CS_BR_FIRE & c_ptr->spells) (void) fprintf(file1, " Breathes Fire Dragon Breath.\n"); } /* Movement for creature */ (void) fprintf(file1, " --Movement =\n"); if ((CM_ALL_MV_FLAGS & c_ptr->cmove) == 0) (void) fprintf(file1, " Do not move.\n"); if (CM_ATTACK_ONLY & c_ptr->cmove) (void) fprintf(file1, " Move only to attack.\n"); if (CM_MOVE_NORMAL & c_ptr->cmove) (void) fprintf(file1, " Move and attack normally.\n"); if (CM_20_RANDOM & c_ptr->cmove) (void) fprintf(file1, " 20%% random movement.\n"); if (CM_40_RANDOM & c_ptr->cmove) (void) fprintf(file1, " 40%% random movement.\n"); if (CM_75_RANDOM & c_ptr->cmove) (void) fprintf(file1, " 75%% random movement.\n"); if (CM_OPEN_DOOR & c_ptr->cmove) (void) fprintf(file1, " Can open doors.\n"); if (CM_PHASE & c_ptr->cmove) (void) fprintf(file1, " Can phase through walls.\n"); (void) fprintf(file1, " --Creature attacks =\n"); attstr = c_ptr->damage; count = 0; while (*attstr != 0 && count < 4) { attype = monster_attacks[*attstr].attack_type; adesc = monster_attacks[*attstr].attack_desc; adice = monster_attacks[*attstr].attack_dice; asides = monster_attacks[*attstr].attack_sides; attstr++; count++; out_val[0] = '\0'; switch (adesc) { case 0: (void) strcpy(out_val, " No hits for "); break; case 1: (void) strcpy(out_val, " Hits for "); break; case 2: (void) strcpy(out_val, " Bites for "); break; case 3: (void) strcpy(out_val, " Claws for "); break; case 4: (void) strcpy(out_val, " Stings for "); break; case 5: (void) strcpy(out_val, " Touches for "); break; case 6: (void) strcpy(out_val, " Kicks for "); break; case 7: (void) strcpy(out_val, " Gazes for "); break; case 8: (void) strcpy(out_val, " Breathes for "); break; case 9: (void) strcpy(out_val, " Spits for "); break; case 10: (void) strcpy(out_val, " Wails for "); break; case 11: (void) strcpy(out_val, " Embraces for "); break; case 12: (void) strcpy(out_val, " Crawls on you for "); break; case 13: (void) strcpy(out_val, " Shoots spores for "); break; case 14: (void) strcpy(out_val, " Begs for money for "); break; case 15: (void) strcpy(out_val, " Slimes you for "); break; case 16: (void) strcpy(out_val, " Crushes you for "); break; case 17: (void) strcpy(out_val, " Tramples you for "); break; case 18: (void) strcpy(out_val, " Drools on you for "); break; case 19: (void) strcpy(out_val, " Insults you for "); break; case 99: (void) strcpy(out_val, " Is repelled."); break; default: (void) strcpy(out_val, " **Unknown value** "); break; } switch (attype) { case 0: (void) strcat(out_val, "no damage."); break; case 1: (void) strcat(out_val, "normal damage."); break; case 2: (void) strcat(out_val, "lowering strength."); break; case 3: (void) strcat(out_val, "confusion."); break; case 4: (void) strcat(out_val, "fear."); break; case 5: (void) strcat(out_val, "fire damage."); break; case 6: (void) strcat(out_val, "acid damage."); break; case 7: (void) strcat(out_val, "cold damage."); break; case 8: (void) strcat(out_val, "lightning damage."); break; case 9: (void) strcat(out_val, "corrosion damage."); break; case 10: (void) strcat(out_val, "blindness."); break; case 11: (void) strcat(out_val, "paralyzation."); break; case 12: (void) strcat(out_val, "stealing money."); break; case 13: (void) strcat(out_val, "stealing object."); break; case 14: (void) strcat(out_val, "poison damage."); break; case 15: (void) strcat(out_val, "lose dexterity."); break; case 16: (void) strcat(out_val, "lose constitution."); break; case 17: (void) strcat(out_val, "lose intelligence."); break; case 18: (void) strcat(out_val, "lose wisdom."); break; case 19: (void) strcat(out_val, "lose experience."); break; case 20: (void) strcat(out_val, "aggravates monsters."); break; case 21: (void) strcat(out_val, "disenchants objects."); break; case 22: (void) strcat(out_val, "eating food."); break; case 23: (void) strcat(out_val, "eating light source."); break; case 24: (void) strcat(out_val, "absorbing charges."); break; case 99: (void) strcat(out_val, "blank message."); break; default: (void) strcat(out_val, "**Unknown value**"); break; } (void) fprintf(file1, "%s (%dd%d)\n", out_val, adice,asides); } for (j = 0; j < 2; j++) (void) fprintf(file1, "\n"); } /* End writing to file */ (void) fclose(file1); prt("Completed.", 0, 0); } } } moria-5.6.debian.1/util/mc/0000755000175000017500000000000011074757472013555 5ustar pjbpjbmoria-5.6.debian.1/util/mc/ERRORS0000644000175000017500000000051605613574151014507 0ustar pjbpjbbefore calling writecreatures in main(), should call a subroutine verifycreatures, i.e. check to make sure no conflicting bits are set would prefer 'a' for cchar instead of "a" prefer exp over xp prefer 2d4 instead of 2 d 4 should be able to specify none/void or similar for empty slots need descriptions for all of the monsters moria-5.6.debian.1/util/mc/creature.y0000644000175000017500000006556011074756221015564 0ustar pjbpjb/* util/mc/creature.y: a Moria creature definition compiler * * Copyright 1989 by Joseph Hall. This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Genral Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ /* This file was also released as part of an independent program, and may be redistributed and/or modified under the authors' original terms, which are given below.*/ /* All rights reserved except as stated below. * This program may contain portions excerpted from Moria which are * copyrighted by others. * * Jim Wilson and any other holders of copyright on substantial portions * of Moria are granted rights to use, modify, and distribute this program * as they see fit, so long as the terms of its use, modification and/or * distribution are no less restrictive than those applying to Moria, * version 5.0 or later, itself, and so long as this use is related to * the further development of Moria. * * Anyone having any other use in mind for this code should contact the * author at 4116 Brewster Dr., Raleigh NC 27606 (jnh@ecemwl.ncsu.edu). */ %{ #include #include #include #include #ifdef ANSI_LIBS #include #else extern double atof(); extern char *malloc(); extern char *calloc(); extern void free(); #endif #include "st.h" #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #define VERBOSE /* to turn on debugging output */ typedef unsigned long int32u; typedef long int32; typedef unsigned short int16u; typedef short int16; typedef unsigned char int8u; typedef struct creature_type { char *name; /* Descrip of creature */ int32u cmove; /* Bit field */ int32u spells; /* Creature spells */ int16u cdefense; /* Bit field */ int16u mexp; /* Exp value for kill */ int8u sleep; /* Inactive counter/10 */ int8u aaf; /* Area affect radius */ int8u ac; /* AC */ int8u speed; /* Movement speed+10 */ int8u cchar; /* Character rep. */ int8u hd[2]; /* Creatures hit die */ int8u damage[4]; /* Type attack and damage*/ int8u level; /* Level of creature */ int32u general; /* general characteristics; not present in usual */ /* moria creature_type */ } creature_type; /* * defined_t is used to indicate whether all fields have been defined */ typedef struct { unsigned move: 1, special: 1, treasure: 1, spell: 1, breath: 1, defense: 1, mexp: 1, sleep: 1, aaf: 1, ac: 1, speed: 1, cchar: 1, hd: 1, damage: 1, level: 1; } defined_t; /* * template_t contains creature definition & flags */ typedef struct { creature_type val; defined_t def; } template_t; /* * attack_t describes a monster attack */ typedef struct { int8u type, desc, dice, sides; } attack_t; /* * symInit_t is used to initialize symbol tables with integer values */ typedef struct { char *name; int32u val; } symInit_t; static symInit_t defenseInit[] = { { "dragon", 0 }, { "animal", 1 }, { "evil", 2 }, { "undead", 3 }, { "frost", 4 }, { "fire", 5 }, { "poison", 6 }, { "acid", 7 }, { "light", 8 }, { "stone", 9 }, { "bit_9", 10 }, { "bit_10", 11 }, { "no_sleep", 12 }, { "infra", 13 }, { "max_hp", 14 }, { "bit_15", 15 }, { NULL, 0 } }; static symInit_t moveInit[] = { { "attack_only", 0 }, { "move_normal", 1 }, { "bit_2", 2 }, { "random_20", 3 }, { "random_40", 4 }, { "random_75", 5 }, { NULL, 0 } }; static symInit_t specialInit[] = { { "invisible", 16 }, { "open_door", 17 }, { "phase", 18 }, { "eats_other", 19 }, { "picks_up", 20 }, { "multiply", 21 }, { "win_creature", 31 }, { NULL, 0 } }; static symInit_t treasureInit[] = { { "carry_obj", 24 }, { "carry_gold", 25 }, { "has_random_60", 26 }, { "has_random_90", 27 }, { "has_1d2_obj", 28 }, { "has_2d2_obj", 29 }, { "has_4d2_obj", 30 }, { NULL, 0 } }; static symInit_t spellInit[] = { { "tel_short", 4 }, { "tel_long", 5 }, { "tel_to", 6 }, { "lght_wnd", 7 }, { "ser_wnd", 8 }, { "hold_per", 9 }, { "blind", 10 }, { "confuse", 11 }, { "fear", 12 }, { "summon_mon", 13 }, { "summon_und", 14 }, { "slow_per", 15 }, { "drain_mana", 16 }, { "bit_17", 17 }, { "bit_18", 18 }, { NULL, 0 } }; static symInit_t breathInit[] = { { "light", 19 }, { "gas", 20 }, { "acid", 21 }, { "frost", 22 }, { "fire", 23 }, { NULL, 0 } }; static symInit_t attackTypeInit[] = { { "normal_damage", 1 }, { "lose_str", 2 }, { "confusion", 3 }, { "cause_fear", 4 }, { "fire_damage", 5 }, { "acid_damage", 6 }, { "cold_damage", 7 }, { "lightning_damage", 8 }, { "corrosion", 9 }, { "cause_blindness", 10 }, { "cause_paralysis", 11 }, { "steal_money", 12 }, { "steal_obj", 13 }, { "poison", 14 }, { "lose_dex", 15 }, { "lose_con", 16 }, { "lose_int", 17 }, { "lose_wis", 18 }, { "lose_exp", 19 }, { "aggravation", 20 }, { "disenchant", 21 }, { "eat_food", 22 }, { "eat_light", 23 }, { "eat_charges", 24 }, { "blank", 99 }, { NULL, 0 } }; static symInit_t attackDescInit[] = { { "hits", 1 }, { "bites", 2 }, { "claws", 3 }, { "stings", 4 }, { "touches", 5 }, { "kicks", 6 }, { "gazes", 7 }, { "breathes", 8 }, { "spits", 9 }, { "wails", 10 }, { "embraces", 11 }, { "crawls_on", 12 }, { "releases_spores", 13 }, { "begs_for_money", 14 }, { "slimes", 15 }, { "crushes", 16 }, { "tramples", 17 }, { "drools_on", 18 }, { "insults", 19 }, { "is_repelled", 99 }, { NULL, 0 } }; /* * Maximum token length = maximum string constant length * Also, trim the stack to an "acceptable" size. */ #define MAX_TOK_LEN 64 /* maximum acceptable token length */ #define YYSTACKSIZE 128 #define GEN_TYPE_TMPL 256 /* type of a template for st */ /* * Globals used by the tokenizer (lexical analyzer) */ #define INPUT_BUF_SIZE 256 static char inputBuf[INPUT_BUF_SIZE] = { 0 }; /* input line buffer */ static char *inputBufp = inputBuf; /* position in input line buffer */ static int lineNo = 0; /* number of current line */ static FILE *input_F; static char tokStr[MAX_TOK_LEN]; /* text of current token */ static int tokType; /* type of current token */ static double tokVal; /* numeric value of current token, */ /* if applicable */ static template_t blankTemplate = { 0 }; /* blank template for init-ing */ static template_t tmpTemplate; /* working template for current */ /* class or creature */ #define MAX_ATTACK 250 static attack_t attackList[MAX_ATTACK] = { 0 }; static int attackCt = 1, creatureAttacks = 0; static int maxCreatureLevel = 0; /* * Global symbol tables */ static st_Table_Pt keywordT_P, /* parser's keywords */ defenseT_P, /* defense flags */ moveT_P, /* movement flags */ specialT_P, /* special flags */ treasureT_P, /* treasure flags */ spellT_P, /* spell flags */ breathT_P, /* breath flags */ attackTypeT_P, /* attack type flags */ attackDescT_P, /* attack desc flags */ classT_P, /* class templates */ creatureT_P; /* creature definitions */ /* * Function declarations */ extern void AddDefense(); extern void NegDefense(); extern void AddMove(); extern void NegMove(); extern void AddTreasure(); extern void NegTreasure(); extern void AddSpecial(); extern void NegSpecial(); extern void AddSpell(); extern void NegSpell(); extern void AddBreath(); extern void NegBreath(); extern void AddAttack(); extern void WriteCreature(); extern void PutClassTemplate(); extern template_t GetClassTemplate(); extern void PutCreature(); %} /* * YACC DEFINITIONS */ /* * The parser's stack can hold ints, doubles, and strings. */ %union { int ival; double dval; char sval[MAX_TOK_LEN]; } /* * Reserved words */ %token CLASS CREATURE NAMED HD D MOVE SPELL BREATH DEFENSE XP CCHAR SLEEP %token RADIUS SPEED ATTACK FOR AC LEVEL TREASURE SPECIAL OF IN /* * Entities */ %token IDENTIFIER /* identifier, not a keyword */ %token FLOAT_LIT /* floating-pt literal */ %token INT_LIT /* integer literal */ %token STRING_LIT /* string literal */ %token BOOL_LIT /* boolean literal */ /* * ASCII chars are their own tokens */ %start creatures /* * THE PARSER */ %% creatures : class_def ';' creatures | creature_def ';' creatures | /* empty */ ; class_def : CLASS IDENTIFIER parent_class '{' features '}' { PutClassTemplate($2, &tmpTemplate); } ; parent_class : ':' IDENTIFIER { tmpTemplate = GetClassTemplate($2); creatureAttacks = 0; } | /* empty */ { tmpTemplate = blankTemplate; creatureAttacks = 0; } ; creature_def : CREATURE STRING_LIT parent_class '{' features '}' { tmpTemplate.val.name = (char *) malloc(strlen($2) + 1); strcpy(tmpTemplate.val.name, $2); PutCreature($2, &tmpTemplate); } ; features : feature ';' features | /* empty */ ; feature : LEVEL ':' INT_LIT { tmpTemplate.val.level = $3; tmpTemplate.def.level = TRUE; } | HD ':' INT_LIT D INT_LIT { tmpTemplate.val.hd[0] = $3; tmpTemplate.val.hd[1] = $5; tmpTemplate.def.hd = TRUE; } | XP ':' INT_LIT { tmpTemplate.val.mexp = $3; tmpTemplate.def.mexp = TRUE; } | CCHAR ':' STRING_LIT { tmpTemplate.val.cchar = $3[0]; tmpTemplate.def.cchar = TRUE; } | AC ':' INT_LIT { tmpTemplate.val.ac = $3; tmpTemplate.def.ac = TRUE; } | SLEEP ':' INT_LIT { tmpTemplate.val.sleep = $3; tmpTemplate.def.sleep = TRUE; } | RADIUS ':' INT_LIT { tmpTemplate.val.aaf = $3; tmpTemplate.def.aaf = TRUE; } | SPEED ':' INT_LIT { tmpTemplate.val.speed = $3 + 10; tmpTemplate.def.speed = TRUE; } | ATTACK ':' attacks | MOVE ':' moves | SPELL ':' spells | SPELL INT_LIT '%' ':' spells { float chance = 100.0 / $2; if (chance > 15.0) chance = 0.0; if (chance < 0.0) chance = 0.0; tmpTemplate.val.spells &= ~0xf; tmpTemplate.val.spells |= (int) ceil(chance); tmpTemplate.def.spell = TRUE; } | BREATH ':' breaths | BREATH INT_LIT '%' ':' breaths { float chance = 100.0 / $2; if (chance > 15.0) chance = 0.0; if (chance < 0.0) chance = 0.0; tmpTemplate.val.spells &= ~0xf; tmpTemplate.val.spells |= (int) ceil(chance); tmpTemplate.def.spell = TRUE; } | DEFENSE ':' defenses | TREASURE ':' carries | SPECIAL ':' specials ; attacks : attack more_attacks ; attack : IDENTIFIER FOR INT_LIT D INT_LIT OF IDENTIFIER { AddAttack($1, $3, $5, $7); } ; more_attacks : ',' attack more_attacks | /* empty */ ; moves : move more_moves ; move : IDENTIFIER { AddMove($1); } | '~' IDENTIFIER { NegMove($2); } ; more_moves : ',' move more_moves | /* empty */ ; spells : spell more_spells | /* empty */ ; spell : IDENTIFIER { AddSpell($1); } | '~' IDENTIFIER { NegSpell($2); } ; more_spells : ',' spell more_spells | /* empty */ ; breaths : breath more_breaths ; breath : IDENTIFIER { AddBreath($1); } | '~' IDENTIFIER { NegBreath($2); } ; more_breaths : ',' breath more_breaths | /* empty */ ; defenses : defense more_defenses ; defense : IDENTIFIER { AddDefense($1); } | '~' IDENTIFIER { NegDefense($2); } ; more_defenses : ',' defense more_defenses | /* empty */ ; carries : carry more_carries ; carry : IDENTIFIER { AddTreasure($1); } | '~' IDENTIFIER { NegTreasure($2); } ; more_carries : ',' carry more_carries | /* empty */ ; specials : special more_specials ; special : IDENTIFIER { AddSpecial($1); } | '~' IDENTIFIER { NegSpecial($2); } ; more_specials : ',' special more_specials | /* empty */ ; %% static symInit_t keywordInit[] = { { "class", CLASS }, { "creature", CREATURE }, { "named", NAMED }, { "hd", HD }, { "d", D }, { "move", MOVE }, { "spell", SPELL }, { "breath", BREATH }, { "defense", DEFENSE }, { "xp", XP }, { "cchar", CCHAR }, { "sleep", SLEEP }, { "radius", RADIUS }, { "speed", SPEED }, { "attack", ATTACK }, { "for", FOR }, { "ac", AC }, { "level", LEVEL }, { "treasure", TREASURE }, { "special", SPECIAL }, { "of", OF }, { "in", IN }, { NULL, 0 } }; /* * MyFGetC-- * fgetc with support for comments * * # is the comment character. comment lasts till end of line. * Spews out an extra char of whitespace at EOF since something seems to * need it. I'll figure this out eventually... */ static int MyFGetC(input_F) FILE *input_F; { static int atEof = FALSE; while (!*inputBufp || (*inputBufp == '#')) { fgets(inputBuf, INPUT_BUF_SIZE, input_F); if (feof(input_F)) return EOF; lineNo++; inputBufp = inputBuf; } return *inputBufp++; } /* * Advance-- * Advance to the next token in the input stream and set tokStr, * tokType, tokVal as appropriate. * * On error, tokType is set to a negative value. */ static void Advance(input_F) FILE *input_F; { register char *tok = tokStr; /* accumulating token string */ register int len = 0; /* length of current token */ static int c = 32; /* current character; ' ' is harmless init */ /* * Skip whitespace in the stream */ while ((c != EOF) && isspace(c)) c = MyFGetC(input_F); /* * At end of file? */ if (c == EOF) { tokType = EOF; strcpy(tokStr, "[EOF]"); return; } /* * Recognize a number [+|-][dddd][.][dddd][{e|E}[+|-]dddd] */ if (isdigit(c) || (c == '.') || (c == '+') || (c == '-')) { register int decPt = FALSE, /* seen a decimal point yet? */ hasExp = FALSE; /* has an exponent? */ if ((c == '-') || (c == '+')) { *tok++ = c; c = MyFGetC(input_F); } while ((len < MAX_TOK_LEN - 1) && (isdigit(c) || (c == '.'))) { if (c == '.') { if (decPt) break; else decPt = TRUE; } *tok++ = c; c = MyFGetC(input_F); len++; } if ((c == 'e') || (c == 'E')) { hasExp = TRUE; *tok++ = c; c = MyFGetC(input_F); len++; if ((c == '-') || (c == '+')) { *tok++ = c; c = MyFGetC(input_F); len++; } while ((len < MAX_TOK_LEN - 1) && isdigit(c)) { *tok++ = c; c = MyFGetC(input_F); len++; } } *tok = 0; if (decPt || hasExp) { tokType = FLOAT_LIT; yylval.dval = atof(tokStr); } else { tokType = INT_LIT; yylval.ival = atoi(tokStr); } return; } /* * Recognize a quoted string */ if (c == '\"') { c = MyFGetC(input_F); while ((len < MAX_TOK_LEN - 1) && (c != EOF) && (c != '\n') && (c != '\"')) { *tok++ = c; c = MyFGetC(input_F); } *tok = 0; c = MyFGetC(input_F); tokType = STRING_LIT; strncpy(yylval.sval, tokStr, MAX_TOK_LEN - 1); yylval.sval[MAX_TOK_LEN - 1] = 0; return; } /* * Recognize an identifier and try to match it with a keyword. * Identifiers begin with a letter and continue in letters and/or * digits. Convert it to lowercase. */ if (isalpha(c) || (c == '_') || (c == '$')) { if (isupper(c)) c = tolower(c); *tok++ = c; c = MyFGetC(input_F); len++; while ((len < MAX_TOK_LEN - 1) && (isalpha(c) || isdigit(c) || (c == '_') || (c == '$'))) { if (isupper(c)) c = tolower(c); *tok++ = c; c = MyFGetC(input_F); len++; } *tok = 0; /* * We've got the identifier; see if it matches any keywords. */ { generic_t gval; int type; if (St_GetSym(keywordT_P, tokStr, &type, &gval) == ST_SYM_FOUND) { tokType = gval.i; strncpy(yylval.sval, tokStr, MAX_TOK_LEN - 1); yylval.sval[MAX_TOK_LEN - 1] = 0; } else if (!strcmp(tokStr, "true")) { tokType = BOOL_LIT; yylval.ival = 1; } else if (!strcmp(tokStr, "false")) { tokType = BOOL_LIT; yylval.ival = 0; } else { tokType = IDENTIFIER; strncpy(yylval.sval, tokStr, MAX_TOK_LEN - 1); yylval.sval[MAX_TOK_LEN - 1] = 0; } } return; } /* * Recognize punctuation */ tokType = c; *tok++ = c; *tok = 0; c = MyFGetC(input_F); return; } void ErrMsg(s) char *s; { int i; fprintf(stderr, "Error: %s at line %d\n", s, lineNo); fprintf(stderr, "%s", inputBuf); for (i = 0; i < inputBufp - inputBuf; i++) { fputc((inputBuf[i] == '\t' ? '\t' : ' '), stderr); } fprintf(stderr, "^ before here\n\n"); } int yyerror(s) char *s; { ErrMsg(s); } int yylex() { Advance(input_F); return(tokType); } void AddSpell(s) char *s; { generic_t gval; int type; char s1[256]; if (St_GetSym(spellT_P, s, &type, &gval) != ST_SYM_FOUND) { sprintf(s1, "unknown spell '%s'", s); ErrMsg(s1); } else { tmpTemplate.val.spells |= (1 << gval.i); tmpTemplate.def.spell = TRUE; } } void NegSpell(s) char *s; { generic_t gval; int type; char s1[256]; if (St_GetSym(spellT_P, s, &type, &gval) != ST_SYM_FOUND) { sprintf(s1, "unknown spell '%s'", s); ErrMsg(s1); } else { tmpTemplate.val.spells &= ~(1 << gval.i); tmpTemplate.def.spell = TRUE; } } void AddBreath(s) char *s; { generic_t gval; int type; char s1[256]; if (St_GetSym(breathT_P, s, &type, &gval) != ST_SYM_FOUND) { sprintf(s1, "unknown breath '%s'", s); ErrMsg(s1); } else { tmpTemplate.val.spells |= (1 << gval.i); tmpTemplate.def.breath = TRUE; } } void NegBreath(s) char *s; { generic_t gval; int type; char s1[256]; if (St_GetSym(breathT_P, s, &type, &gval) != ST_SYM_FOUND) { sprintf(s1, "unknown breath '%s'", s); ErrMsg(s1); } else { tmpTemplate.val.spells &= ~(1 << gval.i); tmpTemplate.def.breath = TRUE; } } void AddSpecial(s) char *s; { generic_t gval; int type; char s1[256]; if (St_GetSym(specialT_P, s, &type, &gval) != ST_SYM_FOUND) { sprintf(s1, "unknown special '%s'", s); ErrMsg(s1); } else { tmpTemplate.val.cmove |= (1 << gval.i); tmpTemplate.def.special = TRUE; } } void NegSpecial(s) char *s; { generic_t gval; int type; char s1[256]; if (St_GetSym(specialT_P, s, &type, &gval) != ST_SYM_FOUND) { sprintf(s1, "unknown special '%s'", s); ErrMsg(s1); } else { tmpTemplate.val.cmove &= ~(1 << gval.i); tmpTemplate.def.special = TRUE; } } void AddMove(s) char *s; { generic_t gval; int type; char s1[256]; if (St_GetSym(moveT_P, s, &type, &gval) != ST_SYM_FOUND) { sprintf(s1, "unknown move '%s'", s); ErrMsg(s1); } else { tmpTemplate.val.cmove |= (1 << gval.i); tmpTemplate.def.move = TRUE; } } void NegMove(s) char *s; { generic_t gval; int type; char s1[256]; if (St_GetSym(moveT_P, s, &type, &gval) != ST_SYM_FOUND) { sprintf(s1, "unknown move '%s'", s); ErrMsg(s1); } else { tmpTemplate.val.cmove &= ~(1 << gval.i); tmpTemplate.def.move = TRUE; } } void AddTreasure(s) char *s; { generic_t gval; int type; char s1[256]; if (St_GetSym(treasureT_P, s, &type, &gval) != ST_SYM_FOUND) { sprintf(s1, "unknown treasure '%s'", s); ErrMsg(s1); } else { tmpTemplate.val.cmove |= (1 << gval.i); tmpTemplate.def.treasure = TRUE; } } void NegTreasure(s) char *s; { generic_t gval; int type; char s1[256]; if (St_GetSym(treasureT_P, s, &type, &gval) != ST_SYM_FOUND) { sprintf(s1, "unknown treasure '%s'", s); ErrMsg(s1); } else { tmpTemplate.val.cmove &= ~(1 << gval.i); tmpTemplate.def.treasure = TRUE; } } void AddDefense(s) char *s; { generic_t gval; int type; char s1[256]; if (St_GetSym(defenseT_P, s, &type, &gval) != ST_SYM_FOUND) { sprintf(s1, "unknown defense '%s'", s); ErrMsg(s1); } else { tmpTemplate.val.cdefense |= (1 << gval.i); tmpTemplate.def.defense = TRUE; } } void NegDefense(s) char *s; { generic_t gval; int type; char s1[256]; if (St_GetSym(defenseT_P, s, &type, &gval) != ST_SYM_FOUND) { sprintf(s1, "unknown defense '%s'", s); ErrMsg(s1); } else { tmpTemplate.val.cdefense &= ~(1 << gval.i); tmpTemplate.def.defense = TRUE; } } int PutAttack(attack) attack_t attack; { register int i; for (i = 0; i < attackCt; i++) { if ((attack.type == attackList[i].type) && (attack.desc == attackList[i].desc) && (attack.dice == attackList[i].dice) && (attack.sides == attackList[i].sides)) { return(i); } } if (attackCt == MAX_ATTACK) { fprintf(stderr, "fatal error: too many different attacks.\n"); fprintf(stderr, "increase MAX_ATTACK.\n"); exit(1); } attackList[attackCt].type = attack.type; attackList[attackCt].desc = attack.desc; attackList[attackCt].dice = attack.dice; attackList[attackCt].sides = attack.sides; return attackCt++; } void AddAttack(s1, dice, sides, s2) char *s1, *s2; int dice, sides; { generic_t gval; int type, aDesc; attack_t attack; char s[256]; if (St_GetSym(attackDescT_P, s1, &type, &gval) != ST_SYM_FOUND) { sprintf(s, "unknown attack description '%s'", s1); ErrMsg(s); return; } else { aDesc = gval.i; } if (St_GetSym(attackTypeT_P, s2, &type, &gval) != ST_SYM_FOUND) { sprintf(s, "unknown attack type '%s'", s2); ErrMsg(s); } else { if (creatureAttacks > 3) { sprintf(s, "creature limited to 4 attacks"); ErrMsg(s); return; } attack.type = gval.i; attack.dice = dice; attack.desc = aDesc; attack.sides = sides; tmpTemplate.val.damage[creatureAttacks++] = PutAttack(attack); tmpTemplate.def.damage = TRUE; } } st_Table_Pt InitTable(name, init) char *name; symInit_t *init; { int i; st_Table_Pt table_P; generic_t gval; table_P = St_NewTable(name, 20); for (i = 0; init[i].name; i++) { gval.i = init[i].val; St_DefSym(table_P, init[i].name, GEN_TYPE_INT, gval); } return table_P; } void InitTables() { int i; generic_t gval; keywordT_P = InitTable("keyword", keywordInit); defenseT_P = InitTable("defense", defenseInit); spellT_P = InitTable("spell", spellInit); moveT_P = InitTable("move", moveInit); specialT_P = InitTable("special", specialInit); breathT_P = InitTable("breath", breathInit); treasureT_P = InitTable("treasure", treasureInit); attackTypeT_P = InitTable("attackType", attackTypeInit); attackDescT_P = InitTable("attackDesc", attackDescInit); classT_P = St_NewTable("class", 40); creatureT_P = St_NewTable("creature", 200); } void WriteCreature(tmpl_P) template_t *tmpl_P; { char s[256]; strcpy(s, "\""); strcat(s, tmpl_P->val.name); strcat(s, "\""); printf("{%-28s, 0x%08x,0x%06x,0x%04x,%5d,%3d,\n", s, tmpl_P->val.cmove, tmpl_P->val.spells, tmpl_P->val.cdefense, tmpl_P->val.mexp, tmpl_P->val.sleep); printf(" %2d, %3d, %2d, '%c', {%3d,%2d}, {%3d,%3d,%3d,%3d}, %3d},\n", tmpl_P->val.aaf, tmpl_P->val.ac, tmpl_P->val.speed, tmpl_P->val.cchar, tmpl_P->val.hd[0], tmpl_P->val.hd[1], tmpl_P->val.damage[0], tmpl_P->val.damage[1], tmpl_P->val.damage[2], tmpl_P->val.damage[3], tmpl_P->val.level); } void WriteCreatures() { char **s_A, **sp; int level, type; generic_t gval; s_A = St_SListTable(creatureT_P); printf("creature_type c_list[MAX_CREATURES] = {\n"); for (level = 0; level <= maxCreatureLevel; level++) { for (sp = s_A; *sp; sp++) { if (St_GetSym(creatureT_P, *sp, &type, &gval) != ST_SYM_FOUND) { fprintf(stderr, "internal err. in WriteCreatures\n"); exit(1); } if ((*(template_t *) gval.v).val.level == level) { WriteCreature((template_t *) gval.v); } } } printf("};\n\n"); St_SListTable(NULL); } void PutClassTemplate(s, tmpl_P) char *s; template_t *tmpl_P; { generic_t gval; char s1[256]; gval.v = malloc(sizeof(template_t)); *(template_t *) gval.v = *tmpl_P; if (St_DefSym(classT_P, s, GEN_TYPE_TMPL, gval) == ST_SYM_FOUND) { sprintf(s1, "attempt to redefine class '%s'", s); ErrMsg(s1); free(gval.v); return; } } template_t GetClassTemplate(s) char *s; { generic_t gval; int type; char s1[256]; if (St_GetSym(classT_P, s, &type, &gval) != ST_SYM_FOUND) { sprintf(s1, "class '%s' undefined\n", s); ErrMsg(s1); return blankTemplate; } else { return *(template_t *) gval.v; } } void NotDefined(name, s) char *name, *s; { printf("Warning: %s not defined for \"%s\", line %d\n", s, name, lineNo); } void PutCreature(s, tmpl_P) char *s; template_t *tmpl_P; { generic_t gval; char s1[256]; gval.v = malloc(sizeof(template_t)); *(template_t *) gval.v = *tmpl_P; if (!tmpl_P->def.move) NotDefined(tmpl_P->val.name, "MOVE"); if (!tmpl_P->def.treasure) NotDefined(tmpl_P->val.name, "TREASURE"); if (!tmpl_P->def.defense) NotDefined(tmpl_P->val.name, "DEFENSE"); if (!tmpl_P->def.mexp) NotDefined(tmpl_P->val.name, "XP"); if (!tmpl_P->def.sleep) NotDefined(tmpl_P->val.name, "SLEEP"); if (!tmpl_P->def.aaf) NotDefined(tmpl_P->val.name, "RADIUS"); if (!tmpl_P->def.ac) NotDefined(tmpl_P->val.name, "AC"); if (!tmpl_P->def.speed) NotDefined(tmpl_P->val.name, "SPEED"); if (!tmpl_P->def.cchar) NotDefined(tmpl_P->val.name, "CCHAR"); if (!tmpl_P->def.hd) NotDefined(tmpl_P->val.name, "HD"); if (!tmpl_P->def.damage) NotDefined(tmpl_P->val.name, "ATTACK"); if (!tmpl_P->def.level) NotDefined(tmpl_P->val.name, "LEVEL"); if (St_DefSym(creatureT_P, s, GEN_TYPE_TMPL, gval) == ST_SYM_FOUND) { sprintf(s1, "attempt to redefine creature '%s'\n", s); ErrMsg(s1); free(gval.v); return; } if (tmpl_P->val.level > maxCreatureLevel) maxCreatureLevel = tmpl_P->val.level; } void WriteAttacks() { int i; printf("struct m_attack_type monster_attacks[N_MONS_ATTS] = {\n"); for (i = 0; i < attackCt; i++) { printf("/* %3d */ { %2d, %2d, %2d, %2d },\n", i, attackList[i].type, attackList[i].desc, attackList[i].dice, attackList[i].sides); }; printf("};\n"); } void WriteConstants() { printf("/* These values should match the values defined in constant.h. */"); printf("\n#define MAX_CREATURES\t%d\n", St_TableSize(creatureT_P)); printf("#define N_MON_ATTS\t%d\n\n", attackCt); } void WriteMonsterHdr() { printf("/* The following code belongs in the file monster.c. */\n\n"); printf("/* The following data was generated by the program in util/mc."); printf("*/\n\n"); } main(argc, argv) int argc; char *argv[]; { char inputFilename[256]; InitTables(); if (argc > 1) { strncpy(inputFilename, argv[1], 255); inputFilename[255] = 0; } else { fprintf(stderr, "input file: "); scanf("%255s", inputFilename); } input_F = fopen(inputFilename, "r"); if (!input_F) { printf("Error: couldn't open file.\n"); exit(1); } if (yyparse()) { printf("Errors prevent continuation.\n"); exit(1); } WriteConstants(); WriteMonsterHdr(); WriteCreatures(); WriteAttacks(); } moria-5.6.debian.1/util/mc/Makefile0000644000175000017500000000050605613574151015207 0ustar pjbpjbCFLAGS = -g mc : creaturec.o symtab.o cc creaturec.o symtab.o -o mc -lm creaturec.o : creaturec.y st.h generic.h yacc creaturec.y cc -c $(CFLAGS) y.tab.c rm y.tab.c mv y.tab.o creaturec.o symtab.o : symtab.c st.h generic.h cc -c $(CFLAGS) symtab.c lintout : symtab.c creaturec.y lint symtab.c creaturec.y > lintout moria-5.6.debian.1/util/mc/generic.h0000644000175000017500000000366111074756221015337 0ustar pjbpjb/* util/mc/generic.h: useful generic union type, used here and there * * Copyright (c) 1989 by Joseph Hall. This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Genral Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ /* This file was also released as part of an independent program, and may be redistributed and/or modified under the authors' original terms, which are given below.*/ /* All rights reserved except as stated below. * * Jim Wilson and any other holders of copyright on substantial portions * of Moria are granted rights to use, modify, and distribute this program * as they see fit, so long as the terms of its use, modification and/or * distribution are no less restrictive than those applying to Moria, * version 5.0 or later, itself, and so long as this use is related to * the further development of Moria. * * Anyone having any other use in mind for this code should contact the * author at 4116 Brewster Dr., Raleigh NC 27606 (jnh@ecemwl.ncsu.edu). */ #ifndef _GENERIC_H_ #define _GENERIC_H_ typedef union { int i; long l; float f; double d; char c; char *s; char **s_A; char *v; } generic_t, *generic_Pt; #define GEN_TYPE_NONE 0 #define GEN_TYPE_INT 1 #define GEN_TYPE_LONG 2 #define GEN_TYPE_FLOAT 3 #define GEN_TYPE_DOUBLE 4 #define GEN_TYPE_CHAR 5 #define GEN_TYPE_STRING 6 #define GEN_TYPE_STRING_A 7 #define GEN_TYPE_VOID_PTR 8 #endif /* _GENERIC_H_ */ moria-5.6.debian.1/util/mc/mon.inf0000644000175000017500000001703705613574151015045 0ustar pjbpjbclass antlion { speed: 1; move: move_normal, random_20; defense: animal, frost, fire; cchar: "A"; treasure: ~carry_obj; sleep: 40; special: eats_other; }; creature "Giant Grey Ant Lion": antlion { level: 26; xp: 90; hd: 19 d 8; radius: 10; ac: 40; attack: bites for 2 d 12 of normal_damage; }; creature "Giant White Ant Lion": antlion { level: 30; xp: 175; hd: 20 d 8; radius: 12; ac: 45; attack: bites for 3 d 10 of cold_damage; defense: ~frost; }; creature "Giant Black Ant Lion": antlion { level: 31; xp: 170; hd: 23 d 8; radius: 14; ac: 45; attack: bites for 2 d 12 of normal_damage, spits for 3 d 6 of acid_damage; }; creature "Giant Red Ant Lion": antlion { level: 35; xp: 350; hd: 23 d 8; radius: 14; ac: 48; attack: bites for 3 d 12 of fire_damage; defense: ~fire, infra; }; creature "Giant Mottled Ant Lion": antlion { level: 36; xp: 350; hd: 24 d 8; radius: 14; ac: 50; attack: bites for 2 d 10 of normal_damage; }; class ant { speed: 1; move: move_normal; defense: animal; cchar: "a"; treasure: ~carry_obj; }; creature "Giant Black Ant": ant { level: 2; xp: 8; hd: 3 d 6; radius: 14; ac: 20; sleep: 40; move: random_20; attack: bites for 1 d 4 of normal_damage; }; creature "Giant White Ant": ant { level: 3; xp: 7; hd: 3 d 6; radius: 8; ac: 16; sleep: 80; attack: hits for 1 d 4 of normal_damage; }; creature "Giant Red Ant": ant { level: 9; xp: 22; hd: 4 d 8; radius: 12; ac: 34; sleep: 60; attack: bites for 1 d 4 of normal_damage, stings for 1 d 4 of lose_str; }; creature "Giant Clear Ant": ant { level: 12; xp: 24; hd: 3 d 7; radius: 12; ac: 18; sleep: 60; special: invisible; attack: bites for 1 d 4 of normal_damage; }; creature "Giant Ebony Ant": ant { level: 15; xp: 3; hd: 3 d 4; radius: 12; ac: 24; sleep: 60; attack: bites for 2 d 3 of normal_damage; special: multiply; }; creature "Giant Silver Ant": ant { level: 23; xp: 45; hd: 6 d 8; radius: 15; ac: 38; sleep: 60; move: random_20; attack: bites for 4 d 4 of acid_damage; }; creature "Giant Static Ant": ant { level: 30; xp: 80; hd: 8 d 8; radius: 10; ac: 40; sleep: 60; move: random_20; attack: bites for 5 d 5 of lightning_damage; }; creature "Giant Hunter Ant": ant { level: 32; xp: 150; hd: 12 d 8; radius: 16; ac: 40; sleep: 1; attack: bites for 4 d 8 of normal_damage; }; class centipede { speed: 1; move: move_normal; defense: ~animal; cchar: "c"; treasure: ~carry_obj; sleep: 50; }; creature "Giant Yellow Centipede" : centipede { level: 1; xp: 2; ac: 12; radius: 8; hd: 2 d 6; attack: bites for 1 d 3 of normal_damage, bites for 1 d 3 of normal_damage; }; creature "Giant White Centipede" : centipede { level: 1; xp: 2; ac: 10; radius: 7; hd: 3 d 5; move: random_20; attack: bites for 1 d 2 of normal_damage, bites for 1 d 2 of normal_damage; }; creature "Metallic Green Centipede" : centipede { speed: 2; level: 2; xp: 3; ac: 4; radius: 5; hd: 4 d 4; move: random_40; attack: crawls_on for 1 d 1 of normal_damage; }; creature "Metallic Blue Centipede" : centipede { speed: 2; level: 3; xp: 7; ac: 6; radius: 6; hd: 4 d 5; move: random_40; attack: crawls_on for 1 d 2 of normal_damage; }; creature "Metallic Red Centipede" : centipede { speed: 2; level: 3; xp: 12; ac: 9; radius: 9; hd: 4 d 8; move: random_20; attack: crawls_on for 1 d 2 of normal_damage; }; creature "Giant Black Centipede" : centipede { level: 4; xp: 11; ac: 20; radius: 8; hd: 5 d 8; move: random_75; attack: bites for 1 d 2 of normal_damage, stings for 1 d 2 of normal_damage; }; creature "Giant Blue Centipede" : centipede { level: 4; xp: 10; ac: 20; radius: 8; hd: 4 d 8; attack: bites for 1 d 3 of normal_damage, stings for 1 d 4 of normal_damage; }; creature "Giant Red Centipede" : centipede { level: 10; speed: 2; xp: 24; ac: 26; radius: 12; hd: 3 d 8; attack: bites for 1 d 2 of normal_damage, stings for 1 d 2 of poison; }; # # here be the dragons # class dragon { defense: evil, dragon, infra; treasure: carry_obj, carry_gold, has_random_60, has_random_90, has_1d2_obj; spell: fear; move: move_normal, random_20; radius: 20; sleep: 50; }; class young_dragon: dragon { ac: 50; spell 10%:; speed: 1; cchar: "d"; attack: claws for 1 d 4 of normal_damage, claws for 1 d 4 of normal_damage, bites for 1 d 6 of normal_damage; }; class mature_dragon: dragon { spell 10%:; speed: 1; cchar: "d"; defense: max_hp; treasure: ~has_1d2_obj, has_2d2_obj; }; creature "Young Blue Dragon": young_dragon { level: 29; xp: 300; hd: 33 d 8; breath: light; }; creature "Young White Dragon": young_dragon { level: 29; xp: 275; hd: 32 d 8; defense: fire; breath: frost; }; creature "Young Green Dragon": young_dragon { level: 29; xp: 290; hd: 32 d 8; breath: gas; }; creature "Young Black Dragon" : young_dragon { level: 35; xp: 600; hd: 32 d 8; ac: 55; defense: max_hp; breath: acid; attack: claws for 1 d 5 of normal_damage, claws for 1 d 5 of normal_damage, bites for 1 d 6 of normal_damage; }; creature "Young Red Dragon" : young_dragon { level: 35; xp: 650; hd: 36 d 8; ac: 60; defense: max_hp, frost; breath: fire; attack: claws for 1 d 8 of normal_damage, claws for 1 d 8 of normal_damage, bites for 2 d 8 of normal_damage; }; creature "Mature White Dragon" : mature_dragon { level: 35; xp: 1000; hd: 48 d 8; ac: 65; attack: claws for 1 d 8 of normal_damage, claws for 1 d 8 of normal_damage, bites for 2 d 8 of normal_damage; }; class ghost { move: move_normal; defense: undead, evil, no_sleep; cchar: "G"; spell 7%:; special: invisible, phase, picks_up; treasure: carry_obj, carry_gold; }; creature "Poltergeist": ghost { level: 3; xp: 6; hd: 2 d 5; treasure: has_random_60, has_random_90; move: random_75, random_40, random_20; spell: tel_short; sleep: 75; radius: 8; ac: 15; speed: 3; attack: hits for 1 d 1 of cause_fear; }; creature "Green Glutton Ghost": ghost { level: 5; xp: 15; hd: 3 d 6; treasure: has_random_60, has_random_90; move: random_75, random_40; spell: tel_short, tel_long; sleep: 10; radius: 10; ac: 20; speed: 3; attack: slimes for 1 d 1 of eat_food; }; creature "Lost Soul": ghost { level: 7; xp: 18; hd: 2 d 8; treasure: has_random_60, has_random_90; move: random_40, random_20; spell: drain_mana, tel_long; sleep: 10; radius: 4; ac: 10; speed: 1; attack: hits for 2 d 2 of normal_damage, touches for 0 d 0 of lose_wis; }; creature "Moaning Spirit": ghost { level: 12; xp: 44; hd: 4 d 8; treasure: has_random_60, has_random_90; move: random_40, random_20; spell: drain_mana, tel_long; sleep: 30; radius: 6; ac: 20; speed: 1; attack: wails for 0 d 0 of cause_fear, touches for 1 d 8 of lose_dex; }; creature "Banshee": ghost { level: 24; xp: 60; hd: 6 d 8; treasure: has_random_60, has_random_90; move: random_40; spell: drain_mana, tel_long; sleep: 10; radius: 20; ac: 24; speed: 2; attack: wails for 0 d 0 of cause_fear, touches for 14 d 8 of lose_exp; }; creature "Ghost": ghost { level: 31; xp: 350; hd: 13 d 8; treasure: has_1d2_obj, has_random_60; move: random_20; spell: drain_mana, tel_long; sleep: 10; radius: 20; ac: 30; speed: 2; defense: max_hp; attack: wails for 0 d 0 of cause_fear, touches for 22 d 8 of lose_exp, claws for 1 d 10 of lose_int; }; creature "Spirit Troll": ghost { level: 34; xp: 425; hd: 15 d 8; treasure: has_1d2_obj, has_random_60; move: random_20; spell: drain_mana, tel_long; sleep: 10; radius: 20; ac: 56; speed: 1; defense: max_hp; attack: claws for 1 d 5 of normal_damage, claws for 1 d 5 of normal_damage, bites for 1 d 6 of normal_damage, touches for 0 d 0 of lose_wis; }; moria-5.6.debian.1/util/mc/st.h0000644000175000017500000000554711074756221014356 0ustar pjbpjb/* util/mc/st.h: definitions for the symbol table module * * Copyright (c) 1989 by Joseph Hall. This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Genral Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ /* This file was also released as part of an independent program, and may be redistributed and/or modified under the authors' original terms, which are given below.*/ /* All rights reserved except as stated below. * * Jim Wilson and any other holders of copyright on substantial portions * of Moria are granted rights to use, modify, and distribute this program * as they see fit, so long as the terms of its use, modification and/or * distribution are no less restrictive than those applying to Moria, * version 5.0 or later, itself, and so long as this use is related to * the further development of Moria. * * Anyone having any other use in mind for this code should contact the * author at 4116 Brewster Dr., Raleigh NC 27606 (jnh@ecemwl.ncsu.edu). */ #ifndef _ST_H_ #define _ST_H_ #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif /* * Needs generic_t */ #include "generic.h" /* * maximum length of symbol strings */ #define ST_MAX_SYM_LEN 32 /* * Struct for individual entries */ typedef struct st_EntryStruct { char name[ST_MAX_SYM_LEN]; /* symbol string */ int type; /* symbol type */ struct st_EntryStruct *next_P; /* next entry in chain */ generic_t gval; /* symbol value */ } st_Entry_t, *st_Entry_Pt; /* * Struct for table header */ typedef struct { char name[ST_MAX_SYM_LEN]; /* table name */ int size, /* size of table to be allocated */ entryCt; /* # of entries in table currently */ st_Entry_Pt *tab_A; /* vector of ptrs to entries */ } st_Table_t, *st_Table_Pt; #define ST_SYM_FOUND 0 #define ST_OK 0 #define ST_SYM_NOT_FOUND 1 #define ST_NULL_TABLE 2 #define ST_MAX_INPUT_LEN 256 /* * functions defined in st_symtab.c */ extern st_Table_Pt St_NewTable(); extern void St_DelTable(); extern int St_GetSym(); extern int St_DefSym(); extern int St_ReplSym(); extern int St_DelSym(); extern st_Table_Pt St_GetTable(); extern void St_DumpTable(); extern char **St_ListTable(); extern char **St_SListTable(); extern int St_TableSize(); #endif /* _ST_H_ */ moria-5.6.debian.1/util/mc/attribut.txt0000644000175000017500000000223305613574150016144 0ustar pjbpjb DEFENSE attributes: dragon animal evil undead frost fire poison acid light stone bit_9 bit_10 no_sleep infra max_hp bit_15 MOVE attributes: attack_only move_normal bit_2 random_20 random_40 random_75 SPECIAL attributes: invisible open_door phase eats_other picks_up multiply win_creature TREASURE attributes: carry_obj carry_gold has_random_60 has_random_90 has_1d2_obj has_2d2_obj has_4d2_obj SPELL attributes: tel_short tel_long tel_to lght_wnd ser_wnd hold_per blind confuse fear summon_mon summon_und slow_per drain_mana bit_17 bit_18 BREATH attributes: light gas acid frost fire ATTACK TYPES: normal_damage lose_str confusion cause_fear fire_damage acid_damage cold_damage lightning_damage corrosion cause_blindness cause_paralysis steal_money steal_obj poison lose_dex lose_con lose_int lose_wis lose_exp aggravation disenchant eat_food eat_light eat_charges blank ATTACK DESCRIPTIONS: hits bites claws stings touches kicks gazes breathes spits wails embraces crawls_on releases_spores begs_for_money slimes crushes tramples drools_on insults is_repelled moria-5.6.debian.1/util/mc/symtab.c0000644000175000017500000003166511074755552015230 0ustar pjbpjb/* util/mc/st_symtab.c: routines for managing symbol tables * * Copyright (c) 1989 by Joseph Hall. This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Genral Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ /* This file was also released as part of an independent program, and may be redistributed and/or modified under the authors' original terms, which are given below.*/ /* All rights reserved except as stated below. * * Jim Wilson and any other holders of copyright on substantial portions * of Moria are granted rights to use, modify, and distribute this program * as they see fit, so long as the terms of its use, modification and/or * distribution are no less restrictive than those applying to Moria, * version 5.0 or later, itself, and so long as this use is related to * the further development of Moria. * * Anyone having any other use in mind for this code should contact the * author at 4116 Brewster Dr., Raleigh NC 27606 (jnh@ecemwl.ncsu.edu). */ #include #include #include #ifdef ANSI_LIBS #include #else extern char *malloc(); extern char *calloc(); extern void free(); extern void cfree(); #endif #include "st.h" /* #define _TESTING_ */ /* * There's a symbol table containing all the names of the symbol tables, * and of course it contains its own name ... * * "tnt" stands for "Table Name Table" ... */ static st_Table_Pt tnt_P = NULL; /* * If there are a lot of symbol tables around you might want to increase * TNT_SIZE. For best results use a prime number. */ #define TNT_SIZE 11 /* * Names of basic generic types. */ #define NAMES 7 /* * Hash-- * Simple, stupid hash function. Why be great, you know, when you can * be adequate so easily? */ static int Hash(s, mod) register char *s; int mod; { register int h = 0; while (*s) h += (unsigned) *s++; return h % mod; } /* * LookupSym-- * Search for a name in a table. Returns NULL if not found. */ static st_Entry_Pt LookupSym(st_P, name) st_Table_Pt st_P; char *name; { st_Entry_Pt entry_P; int h; h = Hash(name, st_P->size); for (entry_P = st_P->tab_A[h]; entry_P; entry_P = entry_P->next_P) if (!strncmp(entry_P->name, name, ST_MAX_SYM_LEN)) break; return entry_P; } /* * AddSym-- * Add a name to a table and return a pointer to the new entry. * ASSUMES THAT NAME DOESN'T EXIST ALREADY IN TABLE (check with LookupSym * above before calling here). */ static st_Entry_Pt AddSym(st_P, name) st_Table_Pt st_P; char *name; { int h; st_Entry_Pt new_P; h = Hash(name, st_P->size); new_P = (st_Entry_Pt) malloc(sizeof(st_Entry_t)); strncpy(new_P->name, name, ST_MAX_SYM_LEN - 1); new_P->name[ST_MAX_SYM_LEN - 1] = 0; new_P->next_P = st_P->tab_A[h]; st_P->tab_A[h] = new_P; st_P->entryCt++; return new_P; } /* * St_NewTable-- * Create a new symbol table header. Returns NULL if name isn't * unique with respect to the symbol tables currently in existence. */ st_Table_Pt St_NewTable(name, size) char *name; int size; { st_Table_Pt st_P; generic_t gval; /* * Create the name table if doesn't already exist. Obviously we * can't use St_NewTable for this ... */ if (!tnt_P) { tnt_P = (st_Table_Pt) malloc(sizeof(st_Table_t)); strncpy(tnt_P->name, "_TNT_", ST_MAX_SYM_LEN - 1); tnt_P->name[ST_MAX_SYM_LEN - 1] = 0; tnt_P->size = TNT_SIZE; tnt_P->tab_A = (st_Entry_Pt *) calloc(TNT_SIZE, sizeof(st_Entry_Pt)); tnt_P->entryCt = 0; gval.v = (char *) tnt_P; St_DefSym(tnt_P, "_TNT_", GEN_TYPE_VOID_PTR, gval); } /* * See if the new table name is unique. */ if (LookupSym(tnt_P, name)) return NULL; /* * Create the new table. */ st_P = (st_Table_Pt) malloc(sizeof(st_Table_t)); strncpy(st_P->name, name, ST_MAX_SYM_LEN - 1); st_P->name[ST_MAX_SYM_LEN - 1] = 0; st_P->size = size; st_P->tab_A = (st_Entry_Pt *) calloc((unsigned) size, sizeof(st_Entry_Pt)); st_P->entryCt = 0; /* * Add the name of the new table to the "table name table" now. * gval.v is a pointer to the new table. */ gval.v = (char *) st_P; St_DefSym(tnt_P, name, GEN_TYPE_VOID_PTR, gval); return st_P; } /* * St_DelTable-- * Delete a symbol table and associated storage. If entries in the * table point to dynamically allocated objects, the user must free these * objects before calling this routine, else the pointers to those objects * will be lost. (** NOTE: this feature has been removed from the version * accompanying the monster compiler, since it isn't needed --jnh **) */ void St_DelTable(st_P) st_Table_Pt st_P; { st_Entry_Pt entry_P; int i; if (!st_P) return; for (i = 0; i < st_P->size; i++) for (entry_P = st_P->tab_A[i]; entry_P; entry_P = entry_P->next_P) { free((char *) entry_P); } if (strncmp(st_P->name, "_TNT_", ST_MAX_SYM_LEN)) St_DelSym(tnt_P, st_P->name); cfree((char *) st_P->tab_A); cfree((char *) st_P); return; } /* * St_ListTable-- * Returns an unsorted list of symbols in the table. The list will be * terminated with a NULL pointer. This routine frees the storage used by * the last call to St_ListTable or St_SListTable; a call with a NULL * argument is a convenient way to free storage allocated by a previous call. */ char **St_ListTable(st_P) st_Table_Pt st_P; { st_Entry_Pt entry_P; int i, j; static char **list_A = NULL, *chars_P = NULL; if (list_A) { free((char *) list_A); free((char *) chars_P); list_A = NULL; chars_P = NULL; } if (!st_P) return NULL; list_A = (char **) malloc(sizeof(char *) * (st_P->entryCt + 1)); chars_P = (char *) malloc(sizeof(char) * ST_MAX_SYM_LEN * st_P->entryCt); for (i = 0; i < st_P->entryCt; i++) list_A[i] = chars_P + ST_MAX_SYM_LEN * i; list_A[st_P->entryCt] = NULL; j = 0; for (i = 0; i < st_P->size; i++) for (entry_P = st_P->tab_A[i]; entry_P; entry_P = entry_P->next_P) strcpy(list_A[j++], entry_P->name); list_A[st_P->entryCt] = NULL; return list_A; } /* * St_SListTable-- * Returns a sorted list of symbols in a table. Otherwise is exactly * like St_ListTable, above. */ char **St_SListTable(st_P) st_Table_Pt st_P; { char **list_A; if (!(list_A = St_ListTable(st_P))) return NULL; qsort(*list_A, st_P->entryCt, sizeof(char) * ST_MAX_SYM_LEN, strcmp); return list_A; } /* * St_GetSym-- * Look for a symbol in a table. Return type and ptr to val if found. */ int St_GetSym(st_P, name, type_P, gval_P) st_Table_Pt st_P; char *name; int *type_P; generic_Pt gval_P; { st_Entry_Pt entry_P; if (!st_P) return ST_NULL_TABLE; if (!(entry_P = LookupSym(st_P, name))) return ST_SYM_NOT_FOUND; *type_P = entry_P->type; *gval_P = entry_P->gval; return ST_SYM_FOUND; } /* * St_DefSym-- * Add a symbol to a table. Returns ST_SYM_FOUND and does nothing if * name is already in table. */ int St_DefSym(st_P, name, type, gval) st_Table_Pt st_P; char *name; int type; generic_t gval; { st_Entry_Pt entry_P; if (!st_P) return ST_NULL_TABLE; if (LookupSym(st_P, name)) return ST_SYM_FOUND; entry_P = AddSym(st_P, name); /* * Assign data. */ entry_P->type = type; entry_P->gval = gval; return ST_SYM_NOT_FOUND; } /* * St_ReplSym-- * Add or supersede a symbol in a table. */ int St_ReplSym(st_P, name, type, gval) st_Table_Pt st_P; char *name; int type; generic_t gval; { st_Entry_Pt entry_P; int status; if (!st_P) return ST_NULL_TABLE; if (!(entry_P = LookupSym(st_P, name))) { entry_P = AddSym(st_P, name); status = ST_SYM_NOT_FOUND; } else { status = ST_SYM_FOUND; } /* * Assign data. */ entry_P->type = type; entry_P->gval = gval; return status; } /* * St_DelSym-- * Delete a symbol from the table. */ int St_DelSym(st_P, name) st_Table_Pt st_P; char *name; { st_Entry_Pt entry_P, last_P; int h; if (!st_P) return ST_NULL_TABLE; h = Hash(name, st_P->size); for (last_P = NULL, entry_P = st_P->tab_A[h]; entry_P; last_P = entry_P, entry_P = entry_P->next_P) if (!strncmp(entry_P->name, name, ST_MAX_SYM_LEN)) break; if (!entry_P) return ST_SYM_NOT_FOUND; if (last_P) last_P->next_P = entry_P->next_P; else st_P->tab_A[h] = NULL; cfree((char *) entry_P); st_P->entryCt--; return ST_SYM_FOUND; } /* * St_GetTable-- * Get a table by name */ st_Table_Pt St_GetTable(name) char *name; { int type; generic_t gval; if (!tnt_P) return NULL; if (St_GetSym(tnt_P, name, &type, &gval) != ST_SYM_FOUND) return NULL; return (st_Table_Pt) gval.v; } /* -Jim Wilson- * St_TableSize-- * Returns the number of entries in the table. */ int St_TableSize(st_P) st_Table_Pt st_P; { return st_P->entryCt; } /* * St_DumpTable-- * Dump a table (for debugging or utility purposes) */ void St_DumpTable(output_F, st_P) FILE *output_F; st_Table_Pt st_P; { st_Entry_Pt entry_P; int bucket; if (!st_P) { fprintf(output_F, "Table ptr is NULL.\n"); return; } fprintf(output_F, "Dumping table '%s', size = %d, count = %d\n", st_P->name, st_P->size, st_P->entryCt); for (bucket = 0; bucket < st_P->size; bucket++) { fprintf(output_F, " Bucket %d:\n", bucket); entry_P = st_P->tab_A[bucket]; if (!entry_P) { fprintf(output_F, " empty\n"); continue; } while (entry_P) { switch(entry_P->type) { case GEN_TYPE_INT: fprintf(output_F, " '%s' = %d (int)\n", entry_P->name, entry_P->gval.i); break; case GEN_TYPE_LONG: fprintf(output_F, " '%s' = %ld (long)\n", entry_P->name, entry_P->gval.l); break; case GEN_TYPE_FLOAT: fprintf(output_F, " '%s' = %e (float)\n", entry_P->name, entry_P->gval.f); break; case GEN_TYPE_DOUBLE: fprintf(output_F, " '%s' = %e (double)\n", entry_P->name, entry_P->gval.d); break; case GEN_TYPE_CHAR: fprintf(output_F, " '%s' = '%c'/%d (char)\n", entry_P->name, entry_P->gval.c, entry_P->gval.c); break; case GEN_TYPE_STRING: if (entry_P->gval.s) fprintf(output_F, " '%s' = '%s' (string)\n", entry_P->name, entry_P->gval.s); else fprintf(output_F, " '%s' = NULL (string)\n", entry_P->name); break; case GEN_TYPE_STRING_A: if (!entry_P->gval.s_A) { fprintf(output_F, " '%s' = NULL (string array)\n", entry_P->name); } else { char **s_A; fprintf(output_F, " '%s' is string array:\n", entry_P->name); for (s_A = entry_P->gval.s_A; *s_A; s_A++) fprintf(output_F, " '%s'\n", *s_A); } break; case GEN_TYPE_VOID_PTR: if (entry_P->gval.v) fprintf(output_F, " '%s' is user type (void ptr)\n", entry_P->name); else fprintf(output_F, " '%s' is NULL user type (void ptr)\n", entry_P->name); break; default: fprintf(output_F, " '%s' is unknown type\n", entry_P->name); break; } entry_P = entry_P->next_P; } } return; } #ifdef _TESTING_ main() { st_Table_Pt st_P; generic_t gval; int type; static char *s_A[] = {"Joe", "Bloe", NULL}; char **list_A; st_P = St_NewTable("Test", 3); gval.i = 10; St_DefSym(st_P, "A", GEN_TYPE_INT, gval); gval.d = 3.14; St_DefSym(st_P, "PI", GEN_TYPE_DOUBLE, gval); gval.i = 1; St_DefSym(st_P, "ONE", GEN_TYPE_INT, gval); gval.s = "Testing!"; St_DefSym(st_P, "TESTING", GEN_TYPE_STRING, gval); gval.c = 7; St_DefSym(st_P, "BELL", GEN_TYPE_CHAR, gval); gval.s_A = s_A; St_DefSym(st_P, "JOE BLOE", GEN_TYPE_STRING_A, gval); St_GetSym(st_P, "A", &type, &gval); printf("A = %d, type = %d\n", gval.i, type); St_GetSym(st_P, "PI", &type, &gval); printf("PI = %f, type = %d\n", gval.d, type); St_DumpTable(stdout, St_GetTable("Test")); St_DelSym(st_P, "TESTING"); St_DumpTable(stdout, St_GetTable("Test")); St_DelSym(st_P, "PI"); gval.s = "Joe Bloe"; St_ReplSym(st_P, "JOE BLOE", GEN_TYPE_STRING, gval); gval.s = "Jane Bloe"; St_ReplSym(st_P, "JANE BLOE", GEN_TYPE_STRING, gval); St_DumpTable(stdout, St_GetTable("Test")); list_A = St_ListTable(St_GetTable("Test")); while (*list_A) printf("'%s'\n", *list_A++); list_A = St_SListTable(St_GetTable("Test")); while (*list_A) printf("'%s'\n", *list_A++); return 0; } #endif moria-5.6.debian.1/util/mergemem/0000755000175000017500000000000011074757475014757 5ustar pjbpjbmoria-5.6.debian.1/util/mergemem/moriadecode.c0000644000175000017500000000270511074755654017377 0ustar pjbpjb/* This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Genral Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ /* NAME moriadecode.c COMMENTS decodes (i.e. xors) a moria.save file this is a filter (reads in stdin, writes in stdout) AUTHOR Eric W. Bazin (currently bazin@carolus.cma.fr) HISTORY bazin - 17/10/1992: Created. */ #include #include main(argc, argv) int argc; char *argv[]; { unsigned char c; unsigned char xor_byte; /* version maj */ (void) scanf("%c",&c); (void) printf("%c",c); /* version min */ (void) scanf("%c",&c); (void) printf("%c",c); /* patch level */ (void) scanf("%c",&c); (void) printf("%c",c); /* xor_byte */ (void) scanf("%c",&c); (void) printf("%c",c); xor_byte = c ; /* rest of file */ while(EOF != scanf("%c",&c)) { (void) printf("%c",c ^ xor_byte); xor_byte = c; } } moria-5.6.debian.1/util/mergemem/README0000644000175000017500000000651411074756013015630 0ustar pjbpjbAUTHOR Eric W. Bazin (currently bazin@carolus.cma.fr) Welcome ! If you read this, you must have successfully uncompressed, uudecoded and detared the MMM directory. MMM stands for Monster Memory Mixing. This package consists in 4 files : moriadecode.c, moriaencode.c, moriamerge.c, and this README file. License : This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Genral Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . The corresponding programs allows to mix the monster memories from two character (each one beeing either saved, dead or having quited) into the memorie of one of the characters. Of course, by repeating the process, every combination is possible. moriadecode is a filter (read inputs on stdin and write outputs on stdout) which transforms a savefile from umoria (typically : moria.sav) in an equivallent decoded file (as umoria savefiles are encoded). moriaencode is the reverse program (also a filter). moriamerge takes two arguments (let's call them file1 and file2) that represents decoded savefiles from umoria (i.e. the result of moriadecode on umoria savefiles) and produce on stdout a decoded moria file corresponding to the character described in file1, but with the additional memory of the character decribed in file2. So, if character1 is saved in moria1.sav, if character2 is saved in moria2.sav, and if we want to lear character1 what character2 knows, we would do : moriadecode < moria1.sav > tmp1 to produce a decoded file tmp1 corresponding to character1 moriadecode < moria2.sav > tmp2 to produce a decoded file tmp2 corresponding to character2 moriamerge tmp1 tmp2 > tmp3 to produce a decoded file tmp3 corresponding to character1 *with the additional memory of character2* moriaencode < tmp3 > moria1.sav to produce the new umoria savefile corresponding to character1 with the additional memory from character2. (Of course, if one wanted also that character2 learn what character1 knows, one would do : moriamerge tmp2 tmp1 > tmp4 moriaencode < tmp4 > moria2.sav ). Warnings/Bugs : a) Theses programs have been writen and tested on Unix system, and on HPS300 computers. I suppose they would work, on other system and computers. b) Theses programs don't check the version of the files submited to them. They have been tested with umoria 5.5 files. I suppose they would work with files from earlier version provided that theses versions are compatibles with umoria 5.5 c) Theses programs don't check if they are "feeded" with encoded or decoded umoria files, so take care of what you do with them. d) The mixing of memory adds the known information of the two characters. In particular, if you mix character with himself, he knows the same monsters, but he will be credited from double kills (and double deaths). Thus, if you want to cheat, go ahead; otherwise, stay righteous ! moria-5.6.debian.1/util/mergemem/moriaencode.c0000644000175000017500000000271211074756221017376 0ustar pjbpjb/* This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Genral Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ /* NAME moriadecode.c COMMENTS encodes (i.e. xors) a decoded moria.save file this is a filter (reads in stdin, writes in stdout) AUTHOR Eric W. Bazin (currently bazin@carolus.cma.fr) HISTORY bazin - 17/10/1992: Created. */ #include #include main(argc, argv) int argc; char *argv[]; { unsigned char c; unsigned char xor_byte; /* version maj */ (void) scanf("%c",&c); (void) printf("%c",c); /* version min */ (void) scanf("%c",&c); (void) printf("%c",c); /* patch level */ (void) scanf("%c",&c); (void) printf("%c",c); /* xor_byte */ (void) scanf("%c",&c); (void) printf("%c",c); xor_byte = c ; /* rest of file */ while(EOF != scanf("%c",&c)) { xor_byte ^= c; (void) printf("%c",xor_byte); } } moria-5.6.debian.1/util/mergemem/moriamerge.c0000644000175000017500000000742111074755711017245 0ustar pjbpjb/* This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Genral Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ /* NAME moriamerge.c COMMENTS usage : moriamerge file1 file2 file1 : decoded moria.save file2 : decoded moria.save output : stdout : merge file2 monster memory into file1. AUTHOR Eric W. Bazin (currently bazin@carolus.cma.fr) HISTORY bazin - 17/10/1992: Created. */ #include #include void rotate(s) unsigned short * s ; { unsigned char c1,c2; c2 = (unsigned char) (*s % 256); c1 = (unsigned char) (*s >> 8); *s = (unsigned short) c2; *s = *s << 8; *s += (unsigned short) c1; } main(argc, argv) int argc; char *argv[]; { FILE * file1; FILE * file2; unsigned char c1[20]; unsigned char c2[20]; unsigned short m1; /* monster number */ unsigned short m2; unsigned short *k1; /* kills */ unsigned short *k2; unsigned short *d1; /* death */ unsigned short *d2; int i; if(argc != 3) { (void) fprintf(stderr,"Error : need 2 input files\n"); exit(1); } if(!(file1=fopen(argv[1],"r"))) { (void) fprintf(stderr,"Error : can't open %s\n",argv[1]); exit(1); } if(!(file2=fopen(argv[2],"r"))) { (void) fprintf(stderr,"Error : can't open %s\n",argv[2]); exit(1); } /* headers */ (void)fread(c1,1,4,file1); (void)fread(c2,1,4,file2); (void)fwrite(c1,1,4,stdout); /* monster memories */ (void)fread(&m1,2,1,file1); rotate(&m1); (void)fread(&m2,2,1,file2); rotate(&m2); while (1) { if(m1 == 0xffff) { while (m2 != 0xffff) { rotate(&m2); (void)fwrite(&m2,2,1,stdout); (void)fread(c2,1,20,file2); (void)fwrite(c2,1,20,stdout); (void)fread(&m2,2,1,file2); rotate(&m2); } goto rest; } else if (m2 == 0xffff) { while (m1 != 0xffff) { rotate(&m1); (void)fwrite(&m1,2,1,stdout); (void)fread(c1,1,20,file1); (void)fwrite(c1,1,20,stdout); (void)fread(&m1,2,1,file1); rotate(&m1); } goto rest; } else { if (m1 < m2) { rotate(&m1); (void)fwrite(&m1,2,1,stdout); (void)fread(c1,1,20,file1); (void)fwrite(c1,1,20,stdout); (void)fread(&m1,2,1,file1); rotate(&m1); } else if (m2 < m1) { rotate(&m2); (void)fwrite(&m2,2,1,stdout); (void)fread(c2,1,20,file2); (void)fwrite(c2,1,20,stdout); (void)fread(&m2,2,1,file2); rotate(&m2); } else { rotate(&m1); (void)fwrite(&m1,2,1,stdout); (void)fread(c1,1,20,file1); (void)fread(c2,1,20,file2); for (i = 0; i < 8; i++) { c1[i] |= c2[i]; } k1 = (unsigned short *) (&(c1[8])); k2 = (unsigned short *) (&(c2[8])); d1 = (unsigned short *) (&(c1[10])); d2 = (unsigned short *) (&(c2[10])); rotate(k1); rotate(k2); rotate(d1); rotate(d2); *k1 += *k2; *d1 += *d2; rotate(k1); rotate(d1); for (i = 12; i < 20; i++) { c1[i] |= c2[i]; } (void)fwrite(c1,1,20,stdout); (void)fread(&m1,2,1,file1); rotate(&m1); (void)fread(&m2,2,1,file2); rotate(&m2); } } } rest: (void)fwrite(&m1,2,1,stdout); while( EOF != fscanf(file1,"%c",c1) ) { printf("%c",c1[0]); } } moria-5.6.debian.1/util/printit/0000755000175000017500000000000011074757476014653 5ustar pjbpjbmoria-5.6.debian.1/util/printit/Makefile0000644000175000017500000000034205613574154016302 0ustar pjbpjbCFLAGS= -c all: pr_items pr_monst pr_items: pr_items.c treasure.o cc pr_items.c treasure.o -o pr_items pr_items > items pr_monst: pr_monst.c monsters.o cc pr_monst.c monsters.o -o pr_monst pr_monst > monsters moria-5.6.debian.1/util/printit/pr_items.c0000644000175000017500000001310211074756221016621 0ustar pjbpjb/* util/printit/pr_items.c: pretty print item/treasure info Copyright (c) 1990-1992: Carlton Hommel, James E. Wilson This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include "config.h" #include "constant.h" #include "types.h" extern treasure_type object_list[]; main() { int i; treasure_type *t; printf("[tval,sub] p1\tLvl $ lbs\t Dam [+, +]\t[AC,+]\tChar Name"); printf("\tFlags\n"); for (i=0; itval, t->subval); if (t->p1) printf("%d\t", t->p1); else printf(" \t"); printf("%2d %4ld %3d\t", t->level, t->cost, t->weight); if (t->damage[0] || t->damage[1]) printf("%2dd%d ", t->damage[0], t->damage[1]); else printf(" "); if (t->tohit || t->todam) printf("[%d, %d]\t", t->tohit, t->todam); else printf(" \t"); if (t->ac!=0 || t->toac!=0) printf("{%d, %d}\t", t->ac, t->toac); else printf(" \t"); printf("'%c' \"%s\"\t", t->tchar, t->name); print_flags(t->tval, t->flags); printf("\n"); } print_flags(tval, flags) char tval; unsigned long flags; { int count; unsigned long mask; if (flags == 0) return; if (tval==80) { printf("<"); for (count=0,mask=0x01; count<32; mask <<= 1, count++) { switch (flags & mask) { case 0x00000001: printf("poison(lvl+rnd(10)) "); break; case 0x00000002: printf("blind(10*lvl+rnd(250)+100) "); break; case 0x00000004: printf("fear(lvl+rnd(10) "); break; case 0x00000008: printf("confused(lvl+rnd(10) "); break; case 0x00000010: printf("hallucinate(25*lvl+rnd(200)+200) ");break; case 0x00000020: printf("cure_poison "); break; case 0x00000040: printf("cure_blindness "); break; case 0x00000080: printf("cure_fear "); break; case 0x00000100: printf("cure_confuse "); break; case 0x00000200: printf("lose_str "); break; case 0x00000400: printf("lose_con "); break; case 0x00000800: printf("lose_int "); break; case 0x00001000: printf("lose_wis "); break; case 0x00002000: printf("lose_dex "); break; case 0x00004000: printf("lose_chr "); break; case 0x00008000: printf("rest_str "); break; case 0x00010000: printf("rest_con "); break; case 0x00020000: printf("rest_int "); break; case 0x00040000: printf("rest_wis "); break; case 0x00080000: printf("rest_dex "); break; case 0x00100000: printf("rest_chr "); break; case 0x00200000: printf("hp+(rnd(6)) "); break; case 0x00400000: printf("hp+(rnd(12)) "); break; case 0x00800000: printf("hp+(rnd(18)) "); break; case 0x01000000: printf("hp+(rnd(3d6)) "); break; case 0x02000000: printf("hp+(rnd(3d12)) "); break; case 0x04000000: printf("hp-(rnd(18)) "); break; case 0x08000000: printf("hp-(rnd(8)) "); break; case 0x10000000: printf("hp-(rnd(2d8)) "); break; case 0x20000000: printf("hp-(rnd(3d8)) "); break; case 0x40000000: printf("??? "); break; case 0x80000000: printf("??? "); break; } } printf(">"); } else if (tval>=TV_MIN_WEAR && tval<=TV_MAX_WEAR) { printf("<"); for (count=0,mask=0x01; count<32; mask <<= 1, count++) { switch (flags & mask) { case TR_STR: printf("Strength "); break; case TR_INT: printf("Intelligence "); break; case TR_WIS: printf("Wisdom "); break; case TR_DEX: printf("Dexterity "); break; case TR_CON: printf("Constitution "); break; case TR_CHR: printf("Charisma "); break; case TR_SEARCH: printf("Searching "); break; case TR_SLOW_DIGEST: printf("Slow_digestion "); break; case TR_STEALTH: printf("Stealth "); break; case TR_AGGRAVATE: printf("Aggravation "); break; case TR_TELEPORT: printf("Teleportation "); break; case TR_REGEN: printf("Regeneration "); break; case TR_SPEED: printf("Speed "); break; case TR_SLAY_DRAGON: printf("Slay_Dragon "); break; case TR_SLAY_ANIMAL: printf("Slay_Animal "); break; case TR_SLAY_EVIL: printf("Slay_Evil "); break; case TR_SLAY_UNDEAD: printf("Slay_Undead "); break; case TR_FROST_BRAND: printf("Cold_Brand "); break; case TR_FLAME_TONGUE: printf("Flame_Brand "); break; case TR_RES_FIRE: printf("Resist_Fire "); break; case TR_RES_ACID: printf("Resist_Acid "); break; case TR_RES_COLD: printf("Resist_Cold "); break; case TR_SUST_STAT: printf("Sustain_Stat "); break; case TR_FREE_ACT: printf("Free_Action "); break; case TR_SEE_INVIS: printf("See_Invisible "); break; case TR_RES_LIGHT: printf("Resist_Lightning "); break; case TR_FFALL: printf("Feather_Fall "); break; case TR_BLIND: printf("Blindness "); break; case TR_TIMID: printf("Timidness "); break; case TR_TUNNEL: printf("Tunneling "); break; case TR_INFRA: printf("Infra_vision "); break; case TR_CURSED: printf("Cursed "); break; } } printf(">"); } } moria-5.6.debian.1/util/printit/pr_monst.c0000644000175000017500000001510611074756221016646 0ustar pjbpjb/* util/printit/pr_monst.c: pretty print monster info Copyright (c) 1990-1992 Carlton Hommel, James E. Wilson This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include "config.h" #include "constant.h" #include "types.h" extern creature_type c_list[]; main() { int i; creature_type *c; printf(" Lvl(Ep) [ HD, AC]\tspd aaf/{sleep}\t\t Name"); printf("\tDamage(special) {Moves} /* Spells */\n"); for (i=0; icchar); printf("%2d", c->level); printf("(%4d) ", c->mexp); printf("[%2dd%d, %2d]\t", c->hd[0], c->hd[1], c->ac); printf("%2d ", ((int)c->speed)-10); printf("%2d/", c->aaf); printf("{%d}\t", c->sleep*10); printf("%20.20s\t", c->name); print_damage(c->damage); printf("\t"); print_flags_cdefense(c->cdefense); printf(" "); print_flags_cmove(c->cmove); printf(" "); print_flags_spells(c->spells); printf("\n"); } print_damage(attstr) int8u attstr[4]; { int attype, adesc, adice, asides; int count; char damstr[50]; extern struct m_attack_type monster_attacks[]; for (count=0; count<4; count++) { if (attstr[count] == 0) continue; attype = monster_attacks[attstr[count]].attack_type; adesc = monster_attacks[attstr[count]].attack_desc; adice = monster_attacks[attstr[count]].attack_dice; asides = monster_attacks[attstr[count]].attack_sides; sprintf(damstr, "%dd%d", adice, asides); switch(attype) { case 1: printf("%s ", damstr); break; case 2: printf("%s(-Str) ", damstr); break; case 3: printf("%s(Conf) ", damstr); break; case 4: printf("%s(Fear) ", damstr); break; case 5: printf("%s(Fire) ", damstr); break; case 6: printf("%s(Acid) ", damstr); break; case 7: printf("%s(Cold) ", damstr); break; case 8: printf("%s(Zap) ", damstr); break; case 9: printf("%s(Acid) ", damstr); break; case 10: printf("%s(Blind) ", damstr); break; case 11: printf("%s(Paral) ", damstr); break; case 12: printf("%s(-Money) ", damstr); break; case 13: printf("%s(-Object) ", damstr);break; case 14: printf("%s(Poison) ", damstr); break; case 15: printf("%s(-Dex) ", damstr); break; case 16: printf("%s(-Con ) ", damstr); break; case 17: printf("%s(-Int ) ", damstr); break; case 18: printf("%s(-Wis) ", damstr); break; case 19: printf("%s(-Exp) ", damstr); break; case 20: printf("%s(Aggr) ", damstr); break; case 21: printf("%s(-Magic) ", damstr); break; case 22: printf("%s(-Food) ", damstr); break; case 23: printf("%s(-Light) ", damstr); break; case 24: printf("%s(-Charges) ", damstr);break; default: case 99: printf("%s(Blank) ", damstr); break; } } } print_flags_spells(spells) unsigned long spells; { int count; unsigned long mask; int chance; if (spells == 0) return; printf("/* "); chance = (int)spells & CS_FREQ; printf("%2.1f%% ", 1.0 / chance * 100.0); for (count=4,mask=0x010; count<32; mask <<= 1, count++) { switch (spells & mask) { case CS_TEL_SHORT: printf("CS_TEL_SHORT ");break; case CS_TEL_LONG: printf("CS_TEL_LONG "); break; case CS_TEL_TO: printf("CS_TEL_TO "); break; case CS_LGHT_WND: printf("CS_LGHT_WND "); break; case CS_SER_WND: printf("CS_SER_WND "); break; case CS_HOLD_PER: printf("CS_HOLD_PER "); break; case CS_BLIND: printf("CS_BLIND "); break; case CS_CONFUSE: printf("CS_CONFUSE "); break; case CS_FEAR: printf("CS_FEAR "); break; case CS_SUMMON_MON: printf("CS_SUMMON_MON ");break; case CS_SUMMON_UND: printf("CS_SUMMON_UND ");break; case CS_SLOW_PER: printf("CS_SLOW_PER "); break; case CS_DRAIN_MANA: printf("CS_DRAIN_MANA ");break; case CS_BR_LIGHT: printf("CS_BR_LIGHT "); break; case CS_BR_GAS: printf("CS_BR_GAS "); break; case CS_BR_ACID: printf("CS_BR_ACID "); break; case CS_BR_FROST: printf("CS_BR_FROST "); break; case CS_BR_FIRE: printf("CS_BR_FIRE "); break; } } printf("*/"); } print_flags_cmove(cmove) unsigned long cmove; { int count; unsigned long mask; if (cmove == 0) return; printf("<"); for (count=0,mask=0x01; count<32; mask <<= 1, count++) { switch (cmove & mask) { case CM_ATTACK_ONLY: printf("CM_ATTACK_ONLY "); break; case CM_MOVE_NORMAL: /*printf("CM_MOVE_NORMAL ");*/ break; case CM_20_RANDOM: printf("CM_20_RANDOM "); break; case CM_40_RANDOM: printf("CM_40_RANDOM "); break; case CM_75_RANDOM: printf("CM_75_RANDOM "); break; case CM_INVISIBLE: printf("CM_INVISIBLE "); break; case CM_OPEN_DOOR: printf("CM_OPEN_DOOR "); break; case CM_PHASE: printf("CM_PHASE "); break; case CM_EATS_OTHER: printf("CM_EATS_OTHER "); break; case CM_PICKS_UP: printf("CM_PICKS_UP "); break; case CM_MULTIPLY: printf("CM_MULTIPLY "); break; case CM_CARRY_OBJ: printf("CM_CARRY_OTHER "); break; case CM_CARRY_GOLD: printf("CM_CARRY_GOLD "); break; case CM_60_RANDOM: printf("CM_60_RANDOM "); break; case CM_90_RANDOM: printf("CM_90_RANDOM "); break; case CM_1D2_OBJ: printf("CM_1D2_OBJ "); break; case CM_2D2_OBJ: printf("CM_2D2_OBJ "); break; case CM_4D2_OBJ: printf("CM_4D2_OBJ "); break; case CM_WIN: printf("CM_WIN "); break; } } printf(">"); } print_flags_cdefense(cdefense) unsigned int cdefense; { int count; unsigned int mask; if (cdefense == 0) return; printf("{"); for (count=0,mask=0x01; count<16; mask <<= 1, count++) { switch (cdefense & mask) { case CD_DRAGON: printf("CD_DRAGON "); break; case CD_ANIMAL: printf("CD_ANIMAL "); break; case CD_EVIL: printf("CD_EVIL "); break; case CD_UNDEAD: printf("CD_UNDEAD "); break; case CD_FROST: printf("CD_FROST "); break; case CD_FIRE: printf("CD_FIRE "); break; case CD_POISON: printf("CD_POISON "); break; case CD_ACID: printf("CD_ACID "); break; case CD_LIGHT: printf("CD_LIGHT "); break; case CD_STONE: printf("CD_STONE "); break; case CD_NO_SLEEP: printf("CD_NO_SLEEP "); break; case CD_INFRA: printf("CD_INFRA "); break; case CD_MAX_HP: printf("CD_MAX_HP "); break; } } printf("}"); } moria-5.6.debian.1/util/monster.cng0000644000175000017500000000716605613574155015345 0ustar pjbpjbFrom djgrabin@phoenix.Princeton.EDU Mon Nov 27 12:37:32 1989 Received: from Princeton.EDU by ernie.Berkeley.EDU (5.61/1.36) id AA09548; Mon, 27 Nov 89 12:35:31 -0800 Received: from phoenix.Princeton.EDU by Princeton.EDU (5.58+++/2.25/mailrelay) id AA03654; Mon, 27 Nov 89 14:42:43 EST Received: by phoenix.Princeton.EDU (5.61/1.95) id AA27562; Mon, 27 Nov 89 14:38:54 -0500 Date: Mon, 27 Nov 89 14:38:54 -0500 From: djgrabin@phoenix.Princeton.EDU (David Joseph Grabiner) Message-Id: <8911271938.AA27562@phoenix.Princeton.EDU> To: wilson@ernie.Berkeley.EDU Subject: Corrections to the monster dictionary Status: RO I have now made the changes I mentioned to you before, plus a few more which I discovered in the process. My current monster dictionary has 161 monsters changed from the original 4.87 copy. I can send you a copy of either my dictionary or the diffs if you want them. However, since your dictionary is in a different form, and I have a different definition of "monster," I would suggest that, if you do use my files, you use them only for reference. Anyway, here is my current list of changes. !is a definite bug; *has been changed. OK, even though they seem wrong: Singing, happy drunk moving 20+40+75 random Ancient red dragon having maximum treasure. Green ooze not moving. This is obviously intentional. Random movement: Some ants are 20%, others aren't. Huge brown bat 75%, four others are 20%. *!Giant fire and giant lightning bat should both be 20% or both be 40%. Long-eared, red, lightning changed to 40, huge brown left alone. *!Giant black centipede should not be 75%, should be 20%. *Fire elemental is 40%, fire spirit and earth spirit not random. All of these made 20. *Moaning spirit is 20%, banshee is 20% and 40%. Moaning spirit made 20+40. *Clear and bloodshot icky-things should be 40%. *Killer beetles vary; should they all be 20%? Should squint-eyed rogue be 20% random? *!Giant black scorpion should be 20%. *!Giant brown tick should be 20%. Doors: *Fire spirit cannot open doors, fire elemental can and shouldn't. *Should golems be able to open doors? *!Oozes shouldn't open doors. *!Spirit troll should open doors. Picking up objects: *!Earth spirit should pick up objects, water elemental shouldn't. *!Warrior shouldn't unless all people do. Treasure: *!Scruffy-looking hobbit should carry gold as well as objects. Why don't quasits carry gold? *!Mature green dragon should be 60+90+2d2, not 60+90+1d2. *!Orc warrior and ogre mage should be 90, like other o's. *Seedy-looking human 1d2 but nasty little gnome only 90, should be 1d2? *!Berzerker should be 1d2, not 60; ninja should be 1d2, not 60+90. *Black knight should be 1d2; sorceror increased to 60+90+1d2, to be consistent with liches. *Should ordinary troll be 60+90, like other trolls? Spell frequency: *!Ancient white is the weakest ancient dragon, should be 9 like ancient green. *!Moaning spirit should be 15, like other ghosts. *!Orc shaman is 5, ogre mage is 6 and should be 5 or less. *Should necromancer be 3 rather than 2, since sorceror is 3? *!Silver jelly and rot jelly shouldn't be harmed by cold. Why are nagas harmed by poison? Acid: *Should flesh golem really be harmed by acid? *Should green jelly, green worm mass really be harmed by acid? Blue light: *Why are flesh golem, giant clear ant, black ooze harmed by light? *!Rot jelly should be harmed by blue light. *!Cloud giant should not be. Should giant purple worm be harmed, like other worms? *Should all undead, or all intelligent undead, be harmed? (Changed to harm L,W,V,G, and spirit troll, not M,s,z.) *Should it be possible to charm/sleep quasits? *!White dragon bat should not be seen by infravision. moria-5.6.debian.1/util/weapons/0000755000175000017500000000000011074757477014637 5ustar pjbpjbmoria-5.6.debian.1/util/weapons/calchits.c0000644000175000017500000001424711074756221016567 0ustar pjbpjb/* util/weapons/calchits.c: calculates relative weapon effectiveness Copyright (c) 1989-1992 Wayne Schlitt, James E. Wilson This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ #include #define max(a,b) ( (a) > (b) ? (a) : (b) ) #define min(a,b) ( (a) < (b) ? (a) : (b) ) #define fabs(a) ( (a) < 0 ? -(a) : (a) ) char blows_table[7][6] = { /* STR/W: 9 18 67 107 117 118 : DEX */ /* <2 */ { 1, 1, 1, 1, 1, 1 }, /* <3 */ { 1, 1, 1, 1, 2, 2 }, /* <4 */ { 1, 1, 1, 2, 2, 3 }, /* <5 */ { 1, 1, 2, 2, 3, 3 }, /* <7 */ { 1, 2, 2, 3, 3, 4 }, /* <9 */ { 1, 2, 2, 3, 4, 4 }, /* >9 */ { 2, 2, 3, 3, 4, 4 } }; /* Weapon weight VS strength and dexterity -RAK- */ void attack_blows(weight, cstr, cdex, max_blows, real_blows, adj_weight ) int weight, cstr, cdex; int *max_blows, *real_blows; int *adj_weight; { int dex_index, str_index; if ((cstr*15) < weight) { *max_blows = 0; *real_blows = 0; *adj_weight = 0.0; } else { if (cdex < 10) dex_index = 0; else if (cdex < 19) dex_index = 1; else if (cdex < 68) dex_index = 2; else if (cdex < 108) dex_index = 3; else if (cdex < 118) dex_index = 4; else dex_index = 5; *adj_weight = ((cstr*10)/weight); if (*adj_weight < 2) str_index = 0; else if (*adj_weight < 3) str_index = 1; else if (*adj_weight < 4) str_index = 2; else if (*adj_weight < 5) str_index = 3; else if (*adj_weight < 7) str_index = 4; else if (*adj_weight < 9) str_index = 5; else str_index = 6; *max_blows = blows_table[6][dex_index]; *real_blows = blows_table[str_index][dex_index]; } } #define calc_chance(low,high,weight) \ max( 0., min( (high - low), \ (high - low) - (high - (650. + weight)) \ ) \ ) / 650. /* Critical hits, Nasty way to die... -RAK- */ int critical_blow(weight, plus, dam, player_level) int weight, player_level; double plus, dam; { int critical; int added_dam; double chance_critical, chance_dam, total_chance; int debug = 0; critical = dam; chance_critical = ( (int)(weight+5*plus+3*player_level) ) / 5000.; if( debug ) printf( "chance_critical=%g chance_dam=(", chance_critical ); chance_dam = calc_chance( weight, 400., weight ); if( debug ) printf( "%g", chance_dam ); total_chance = chance_dam; added_dam = (2*dam + 5) * chance_dam; chance_dam = calc_chance( 400., 700., weight ); if( debug ) printf( "+%g", chance_dam ); total_chance += chance_dam; added_dam += (3*dam + 10) * chance_dam; chance_dam = calc_chance( 700., 900., weight ); if( debug ) printf( "+%g", chance_dam ); total_chance += chance_dam; added_dam += (4*dam + 15) * chance_dam; chance_dam = calc_chance( 900., 2000., weight ); if( debug ) printf( "+%g) ", chance_dam ); total_chance += chance_dam; added_dam += (5*dam + 20) * chance_dam; if( debug ) printf( "added_dam = %d\n", added_dam ); if( fabs( total_chance - 1. ) > 1e-14 ) { printf( "ERROR: total_chance=%g (%g)\n", total_chance, total_chance - 1. ); exit( 1 ); } return( critical + added_dam * chance_critical ); } int get_stat( stat ) int *stat; { int tmp, c; if( 1 != scanf( " %d", &tmp ) ) return( 0 ); *stat = tmp; if( tmp == 18 ) { c = getchar(); if( c == '/' ) { if( 1 != scanf( "%d", &tmp ) ) return( 0 ); *stat += tmp; } else ungetc(c, stdin); } return( 1 ); } #define MWEAPONS 100 int main() { int cstr, cdex, player_level; int weight[MWEAPONS]; double to_hit[MWEAPONS], to_dam[MWEAPONS], weapon_dam[MWEAPONS]; int num_weapons, i; int max_blows, real_blows; int adj_weight; double avg_dam, critical; int num_die, die_sides; printf( "Enter level of your character: " ); if( 1 != scanf( " %d", &player_level ) ) { putchar( '\n'); exit( 1 ); } printf( "Enter number of weapons: " ); if( 1 != scanf( " %d", &num_weapons ) ) { putchar( '\n'); exit( 1 ); } for( i = 0; i < num_weapons; i++ ) { printf( "Enter weight, weapon_dam, to_hit, to_dam for weapon #%d: ", i ); if( 5 != scanf( " %d %dd%d %lf %lf", &weight[i], &num_die, &die_sides, &to_hit[i], &to_dam[i] ) ) { putchar( '\n'); exit( 1 ); } weapon_dam[i] = ( num_die * die_sides + num_die )/2.; } while( 1 ) { printf( "Enter cstr, cdex: " ); if( !get_stat( &cstr ) || !get_stat( &cdex ) ) { putchar( '\n'); exit( 1 ); } if( cstr == 0 && cdex == 0 ) break; printf( " Weapon | Max blows | Blows | weight ratio | hp of dam |"); printf( " w/ critical |\n" ); for( i = 0; i < num_weapons; i++ ) { attack_blows( weight[i], cstr, cdex, &max_blows, &real_blows, &adj_weight ); #if 0 /* multiply to dam bonuses by max/real number of hits */ if (real_blows != 0) avg_dam = (int) (real_blows*(weapon_dam[i]+ (max_blows * (int)to_dam[i] / real_blows))); else avg_dam = 0; critical = critical_blow( weight[i], to_hit[i], avg_dam, player_level ); #else /* this is the old way, to_dam added after critical */ avg_dam = (int) (real_blows*weapon_dam[i]); critical = critical_blow( weight[i], to_hit[i], avg_dam, player_level ); avg_dam += (int) real_blows*to_dam[i]; critical += (int) real_blows*to_dam[i]; #endif printf( " %4d | %6d | %4d | %8d | %6g | %7g |\n", i, max_blows, real_blows, adj_weight, avg_dam, critical ); } printf( "\n" ); } return( 0 ); } moria-5.6.debian.1/util/weapons/ERRORS0000644000175000017500000000056305613574154015571 0ustar pjbpjbthe program is a bit simplistic, as it does not consider monster AC, and does not correctly handle weapons that are too heavy to wield properly the README, dragon.inf, and weapons.lst files are probably out of date, and need to be updated the README file contains info that doesn't belong here, perhaps create a hints file in the doc directory that contains this info? moria-5.6.debian.1/util/weapons/highchar.in0000644000175000017500000000153205613574152016732 0ustar pjbpjb36 44 160 1d8 10 10 95 1d9 10 10 150 2d4 10 10 140 3d4 10 10 180 2d8 10 10 170 3d4 10 10 180 2d6 10 10 160 2d6 10 10 150 2d5 10 10 40 1d4 10 10 110 1d7 10 10 20 1d4 10 10 30 1d5 10 10 15 1d4 10 10 12 1d4 10 10 260 4d5 10 10 170 1d10 10 10 150 2d6 10 10 30 1d5 10 10 190 2d6 10 10 190 3d4 10 10 30 1d4 10 10 120 3d4 10 10 300 2d8 10 10 130 1d10 10 10 120 2d5 10 10 120 2d4 10 10 180 3d4 10 10 150 2d6 10 10 160 2d5 10 10 40 1d6 10 10 50 1d7 10 10 75 1d6 10 10 50 1d6 10 10 100 1d7 10 10 80 1d6 10 10 280 3d6 10 10 200 3d6 10 10 180 3d6 10 10 240 4d5 10 10 200 4d4 10 10 280 4d6 10 10 120 3d3 10 10 100 1d3 10 10 18/100 18/100 moria-5.6.debian.1/util/weapons/Makefile0000644000175000017500000000035705613574152016271 0ustar pjbpjb all: calchits calchits: calchits.c $(CC) $(CFLAGS) $@.c $(LDFLAGS) -o $@ clean: -rm -f >&/dev/null *.o dist: shar README Makefile calchits.c dragon.inf weapon.lst \ mkallwpn mkallwpn.lst highchar.in lowchar.in >calchit.shr moria-5.6.debian.1/util/weapons/mkallwpn0000744000175000017500000000057705613574153016407 0ustar pjbpjb#!/bin/sh # # this shell script will generate a formated list of what all weapons will # do in=$1 out=`basename $in .in`.out echo -n " Name | Mblow | Blows | wt ratio |" >$out echo " dam | w/ critical |" >>$out calchits <$in \ | sed -n -e "2,45p" | cut -c15-17,19-30,35-45,49-53,57- | \ paste -d" " mkallwpn.lst - | sort -t"|" -bnr +5 -6 >>$out moria-5.6.debian.1/util/weapons/README0000644000175000017500000002501605613574152015510 0ustar pjbpjb > > Here's a question for all of you who have had experiences with HA's. Is a > dagger a better weapon than say, a war hammer or an axe? I've found a > bodkin [+8,+8] and a war hammer [+7,+8], and found that the dagger sold > for more in the stores. Why? Just because it is one up on To-Hit?? To me, > it would seem like the war hammer is a way better weapon... Well, the > difference between the prices is about 1000 gp. > ok, here are some spoilers. 1) dont trust what the store will buy or sell things for as being a good indicator of its true value. they basis it only on the base value of a weapon, the to-hit and to-damage, and the special abilities it has. these are _not_ always what makes a weapon really good, and what might be good for one character may be bad for another. 2) when in doubt, keep the dagger. daggers are probably best for all types of characters (mages, warriors etc) until you get your strength and dexterity up real high. a detail explanation of how things work follows... the amount of damage that a weapon will do is based on the following things: * the weight of the weapon. the lighter it is the more likely you will get two hits in for each attack. on the other hand, the heavier the weapon, the more likely you are to get a critical hit (good, excellent, great hits). * the basic amount of damage the weapon does. most daggers do 1d4, two handed swords (Zweihander) do 4d6. * your total to-hit. this includes the pluses that come with your weapon, the minuses that your armor does, any rings of to-hit or slaying, etc. the higher your total to-hit is, the more likely you are to get a critical blow. * your total to-damage. like your total to-hit, this includes everything. when you get a really good character, this will usually dominate over the weapons basic damage. * your current strength. the stronger you are the easier it is for you to get several hits per attack. * your current dexterity. the more dextrous you are the more hits per attack you are capable of. * the level of your character. the more experience you have the more likely you are to get a "good (x2)" or "excellent (x3)" hit. all of these things are mixed together in a rather complicated way. i had to write a program that takes all of these factors into account and gives a true indication of which weapon is better. (i had two HA's that i couldnt decide between. it turned out that depending on my current strength and dex either one could be much better than the other. i ended up keeping both of them until both my str and dex were 18/100.) the chance that you actually hit the monster is based on: * your "base to hit". this is based on what race your character is and ranges from -10 for Halflings to 20 for Half-Trolls. it also depends on what "class" your character is and these bonuses range from 20 for mages to 70 for paladin's. (warriors arent much behind with a bonus of 68). a human mage will have a "base to hit" of 20, a half troll warrior will have a "base to hit" of 88. * your current level. the more experience you have, the more likely you are to hit the monster. going up one level is equivalent to enchanting your weapon's to-hit by one. * your total to-hit. the higher your total to-hit, the more likely you are to hit the monster * the monsters ac (armor class). the higher the monster's ac, the less likely you are to hit the monster. this varies a lot from monster to monster. most worm masses, mushrooms, jellies and stuff have ac's under 10. most of the ancient dragons have ac's in the 80-100 range. the balrog has an ac of 125, the highest of any monster. iron golems have an ac of 99, which can give you some idea of how hard it would be to hit a ancient dragon without taking too many risks. most of the other monsters seem to to be in the 30-60 range. the formula for this is: val = bth + 3*level + 3*tohit if a random number between 1 and val is greater than the monsters ac, then you hit, otherwise you miss. you will always hit one out of 20 times, even if your weapon is too heavy for you to wield. i dont have anything to calculate calculate your chances to hit monsters because there are just too many different cases. a level 40 half-troll warrior with a total to hit of 30 would have a two out of three chance of hitting a AMHD. everyone else is going to going to be well under 50-50. The program "calc_hits" can help you figure out which weapon is better for you now, and as your strength and dexterity goes up. it is based on the source code to moria so it should be basically correct. calc_hits isnt a fancy program and it handles errors by stopping the program. it is designed to be used by the person who wrote it. :-> probably the best way to explain how to run the program is simply to give you an example run comparing a bastard sword, a dagger (stiletto) and a two handed great flail. all of them will be (+3,+4) giving you a total to-hit of 2 and a total to-damage of 4. the results are given in a table form with the following field: Mblow is the maximum number of blows you can get per attack. it is based only on your dex. Blows is the number of plows you can get with your current strength based on the Mblows, and strength/weight ratio. wt ratio is your strength to weight of weapon ratio. a ratio above 10 doesnt do you any more good than a ratio of 10. if the ratio is under 2, you can only get one blow no matter what your dex is. dam is the amount of damage that you get, on the average if you hit with every blow and dont get a critical hit. w/ critical is the amount of damage you get on the average if you include the possibilities of getting a critical hit. for low level characters, this rarely makes a difference. for high level characters, this can make a real difference. (wayne 6) % calc_hits Enter level of your character: 12 Enter number of weapons: 3 Enter weight, weapon_dam, to_hit, to_dam for weapon #0: 140 3d4 2 4 Enter weight, weapon_dam, to_hit, to_dam for weapon #1: 12 1d4 2 4 Enter weight, weapon_dam, to_hit, to_dam for weapon #2: 280 3d6 2 4 Enter cstr, cdex: 11 14 | Weapon | Max blows | Blows | weight ratio | hp of dam | w/ critical | | 0 | 2 | 1 | 0 | 11 | 12 | | 1 | 2 | 2 | 9 | 13 | 13 | | 2 | 0 | 0 | 0 | 0 | 0 | Enter cstr, cdex: 17 18 | Weapon | Max blows | Blows | weight ratio | hp of dam | w/ critical | | 0 | 2 | 1 | 1 | 11 | 12 | | 1 | 2 | 2 | 14 | 13 | 13 | | 2 | 0 | 0 | 0 | 0 | 0 | Enter cstr, cdex: 18/20 18/10 | Weapon | Max blows | Blows | weight ratio | hp of dam | w/ critical | | 0 | 3 | 2 | 2 | 23 | 25 | | 1 | 3 | 3 | 31 | 19 | 19 | | 2 | 3 | 1 | 1 | 14 | 17 | Enter cstr, cdex: 18/100 18/100 | Weapon | Max blows | Blows | weight ratio | hp of dam | w/ critical | | 0 | 6 | 4 | 8 | 46 | 50 | | 1 | 6 | 5 | 98 | 32 | 32 | | 2 | 6 | 3 | 4 | 43 | 52 | Enter cstr, cdex: (wayne 7) % exit there is a second program called "mk_all_weapon" that generates a list of how much damage all weapons will do given a certain character. it is useful for getting a feel of which weapons are good and why. for low level characters, the following are the top 5 weapons: character level of 12 total to-hit and to-damage of +7 strength of 11. these numbers wont change much until you get above 18 dexterity of 17. these numbers will be the same unless your dex is above 18/01 or below 10. Name | Mblow | Blows | wt ratio | dam | w/ critical | Dagger (Stiletto) | 2 | 2 | 9 | 19 | 19 | Dagger (Misercorde) | 2 | 2 | 7 | 19 | 19 | Dagger (Bodkin) | 2 | 2 | 5 | 19 | 19 | Morningstar | 2 | 1 | 0 | 14 | 15 | Katana | 2 | 1 | 0 | 14 | 15 | the bottom 5 for a low level character: Fauchard | 0 | 0 | 0 | 0 | 0 | Executioner's Sword | 0 | 0 | 0 | 0 | 0 | Beaked Axe | 0 | 0 | 0 | 0 | 0 | Battle Axe (European) | 0 | 0 | 0 | 0 | 0 | Battle Axe (Balestarius) | 0 | 0 | 0 | 0 | 0 | for high level characters, the following are the top 5 weapons: character level of 36 total to-hit and to-damage of +20 strength of 18/100. dexterity of 18/100. Name | Mblow | Blows | wt ratio | dam | w/ critical | Katana | 6 | 5 | 9 | 137 | 161 | War Hammer | 6 | 5 | 9 | 130 | 153 | Lucerne Hammer | 6 | 5 | 9 | 130 | 153 | Two Handed Sword (Claymore) | 6 | 4 | 5 | 122 | 151 | Two Handed Sword (No-Dachi) | 6 | 4 | 5 | 120 | 149 | the bottom 5 Two Handed Great Flail | 6 | 3 | 4 | 91 | 120 | Ball and Chain | 6 | 4 | 7 | 100 | 120 | Awl-Pike | 6 | 4 | 7 | 98 | 118 | Lance | 6 | 3 | 3 | 87 | 117 | Fauchard | 6 | 4 | 6 | 84 | 102 | the katana tends to be at or near the top for all characters at all times. if you get even a poor katana (HA) or (DF), keep it and enchant it. one of the biggest mistakes people do is get rid of the weapon that the start with and try to get a "bigger meaner" weapon. dont. just enchant your original weapon until you get something really good. i dont consider the (FT), (FB), (SD), (SE) and (SU) as "really good". i consider the "(SM)" good, only if i dont already have something of see invisible. (HA) and (DF)'s i keep if they are better than the ones i already have. -wayne moria-5.6.debian.1/util/weapons/medchar.in0000644000175000017500000000137205613574154016564 0ustar pjbpjb20 44 160 1d8 6 6 95 1d9 6 6 150 2d4 6 6 140 3d4 6 6 180 2d8 6 6 170 3d4 6 6 180 2d6 6 6 160 2d6 6 6 150 2d5 6 6 40 1d4 6 6 110 1d7 6 6 20 1d4 6 6 30 1d5 6 6 15 1d4 6 6 12 1d4 6 6 260 4d5 6 6 170 1d10 6 6 150 2d6 6 6 30 1d5 6 6 190 2d6 6 6 190 3d4 6 6 30 1d4 6 6 120 3d4 6 6 300 2d8 6 6 130 1d10 6 6 120 2d5 6 6 120 2d4 6 6 180 3d4 6 6 150 2d6 6 6 160 2d5 6 6 40 1d6 6 6 50 1d7 6 6 75 1d6 6 6 50 1d6 6 6 100 1d7 6 6 80 1d6 6 6 280 3d6 6 6 200 3d6 6 6 180 3d6 6 6 240 4d5 6 6 200 4d4 6 6 280 4d6 6 6 120 3d3 6 6 100 1d3 6 6 18 18 moria-5.6.debian.1/util/weapons/weapon.lst0000644000175000017500000000652305613574153016650 0ustar pjbpjb Name Symbol Price Weight Damage Level V V V V V V Awl-Pike '/' 340 160 1d8 8 Backsword '|' 60 95 1d9 7 Ball and Chain '\' 200 150 2d4 20 Bastard Sword '|' 350 140 3d4 14 Battle Axe (Balestarius) '\' 500 180 2d8 30 Battle Axe (European) '\' 334 170 3d4 13 Beaked Axe '/' 408 180 2d6 15 Broad Axe '\' 304 160 2d6 17 Broadsword '|' 255 150 2d5 9 Cat-O-Nine Tails '\' 14 40 1d4 3 Cutlass '|' 85 110 1d7 7 Dagger (Bodkin) '|' 10 20 1d4 1 Dagger (Main Gauche) '|' 25 30 1d5 2 Dagger (Misercorde) '|' 10 15 1d4 0 Dagger (Stiletto) '|' 10 12 1d4 0 Executioner's Sword '|' 850 260 4d5 40 Fauchard '/' 376 170 1d10 17 Flail '\' 353 150 2d6 12 Foil '|' 35 30 1d5 2 Glaive '/' 363 190 2d6 20 Halberd '/' 430 190 3d4 22 Javelin '/' 18 30 1d4 4 Katana '|' 400 120 3d4 18 Lance '/' 230 300 2d8 10 Longsword '|' 300 130 1d10 12 Lucerne Hammer '/' 376 120 2d5 11 Mace '\' 130 120 2d4 6 Mace (Lead filled) '\' 502 180 3d4 15 Morningstar '\' 396 150 2d6 10 Pike '/' 358 160 2d5 15 Rapier '|' 42 40 1d6 4 Sabre '|' 50 50 1d7 5 Small Sword '|' 48 75 1d6 5 Spear '/' 36 50 1d6 5 Thrusting Sword (Baselard) '|' 80 100 1d7 5 Thrusting Sword (Bilbo) '|' 60 80 1d6 4 Two Handed Great Flail '\' 590 280 3d6 45 Two Handed Sword (Claymore) '|' 775 200 3d6 30 Two Handed Sword (Espadon) '|' 655 180 3d6 35 Two Handed Sword (Flamberge) '|' 1000 240 4d5 45 Two Handed Sword (No-Dachi) '|' 675 200 4d4 45 Two Handed Sword (Zweihander) '|' 1000 280 4d6 50 War Hammer '\' 225 120 3d3 5 Wooden Club '\' 1 100 1d3 0 Holy Avenger: (HA) increase strength (P1), slay evil, slay undead, sustain stat (P1), see invisible Defender: (DF) stealth, regeneration, resist fire, resist acid, resist cold, resist lightning, free action, see invisible, feather fall Slay Monster: (SM) slay monster, see invisible Helmet of the Magi: (0x01380008) increase intelligence (P1), resist fire, resist acid, resist cold, see invisible Amulet of the Magi: (0x01800040) free action, see invisible, searching moria-5.6.debian.1/util/weapons/mkallwpn.lst0000644000175000017500000000260005613574153017174 0ustar pjbpjbAwl-Pike | Backsword | Ball and Chain | Bastard Sword | Battle Axe (Balestarius) | Battle Axe (European) | Beaked Axe | Broad Axe | Broadsword | Cat-O-Nine Tails | Cutlass | Dagger (Bodkin) | Dagger (Main Gauche) | Dagger (Misercorde) | Dagger (Stiletto) | Executioner's Sword | Fauchard | Flail | Foil | Glaive | Halberd | Javelin | Katana | Lance | Longsword | Lucerne Hammer | Mace | Mace (Lead filled) | Morningstar | Pike | Rapier | Sabre | Small Sword | Spear | Thrusting Sword (Baselard) | Thrusting Sword (Bilbo) | Two Handed Great Flail | Two Handed Sword (Claymore) | Two Handed Sword (Espadon) | Two Handed Sword (Flamberge) | Two Handed Sword (No-Dachi) | Two Handed Sword (Zweihander) | War Hammer | Wooden Club | moria-5.6.debian.1/util/weapons/lowchar.in0000644000175000017500000000137205613574153016617 0ustar pjbpjb10 44 160 1d8 3 3 95 1d9 3 3 150 2d4 3 3 140 3d4 3 3 180 2d8 3 3 170 3d4 3 3 180 2d6 3 3 160 2d6 3 3 150 2d5 3 3 40 1d4 3 3 110 1d7 3 3 20 1d4 3 3 30 1d5 3 3 15 1d4 3 3 12 1d4 3 3 260 4d5 3 3 170 1d10 3 3 150 2d6 3 3 30 1d5 3 3 190 2d6 3 3 190 3d4 3 3 30 1d4 3 3 120 3d4 3 3 300 2d8 3 3 130 1d10 3 3 120 2d5 3 3 120 2d4 3 3 180 3d4 3 3 150 2d6 3 3 160 2d5 3 3 40 1d6 3 3 50 1d7 3 3 75 1d6 3 3 50 1d6 3 3 100 1d7 3 3 80 1d6 3 3 280 3d6 3 3 200 3d6 3 3 180 3d6 3 3 240 4d5 3 3 200 4d4 3 3 280 4d6 3 3 120 3d3 3 3 100 1d3 3 3 11 15 moria-5.6.debian.1/INSTALL0000644000175000017500000000373111074760000013213 0ustar pjbpjb First, you have to put every file in the 'source' directory, and every file in your machine/OS specific directory into a common directory. If you are on a UNIX machine and running csh, the following works nicely if typed from this directory; note that unix/Makefile is built for Debian, so you need the original UNIX Makefile to make on other Unix systems. ****** foreach i (source/* unix/*) ln -s $i $i:t rm Makefile ln -s unix/Makefile.unix Makefile end ****** (If you wish to build the program in a temporary directory, the same command will work, but you will have to give full pathnames for the source and unix directories. If you build the program in a different filesystem than the one containing the sources, then 'ln -s' will only work if you have BSD or SYSVR4. If the 'ln -s' fails, you can use 'ln' or 'cp' instead.) To compile the program, edit the config.h file and Makefile to change the names of the files the game uses. Also, uncomment the appropriate line for the system you are compiling on. Type make (or build or whatever) to compile the game. You may want to edit the 'files/hours' file to indicate during what hours people are allowed to play the game. (The micro versions don't use this file.) The game needs to be installed setuid on UNIX systems for the scoreboard to work. Use the command 'chmod 4511 moria' to do this. The file scores should be mode 644 with the same owner as moria. The files hours and news must be publicly readable with mode 444. (Or just type 'make install' after setting BINDIR and LIBDIR in the Makefile to appropriate values.) There are two choices for the key bindings, the original style and a rogue-like style. You can choose which one is to be the default by changing the value of ROGUE_LIKE in config.h. Moria only has partial support for SYS III. It probably won't compile and run under this system without a bit of work. If your compiler has a seven character identifier limit, the shortnam.sed file should solve the problem nicely. moria-5.6.debian.1/doc/0000755000175000017500000000000011074757445012746 5ustar pjbpjbmoria-5.6.debian.1/doc/moria1.txt0000644000175000017500000014045211074751716014700 0ustar pjbpjb The Dungeons of Moria Robert Alan Koeneke James E. Wilson David J. Grabiner Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . October 13, 2008 The Dungeons of Moria Robert Alan Koeneke James E. Wilson David J. Grabiner 1. Introduction The game of moria is a single player dungeon simulation. A player may choose from a number of races and classes when creat- ing a character, and then `run' that character over a period of days, weeks, even months, attempting to win the game by defeating the Balrog which lurks in the deeper levels. The player will begin his adventure on the town level where he may acquire supplies, weapons, armor, and magical devices by bar- tering with various shop owners. After preparing for his adven- ture, the player can descend into the dungeons of moria where fantastic adventures await his coming! Before beginning your first adventure, you should read this docu- ment carefully. The game of moria is a complicated game, and will require a dedicated player to win. 2. The Character All characters have six main attributes which modify their basic abilities. These six attributes, called stats, are strength, intelligence, wisdom, dexterity, constitution, and charisma. Stats may vary from a minimum of 3 to a maximum of 18. At the highest level, stats are further qualified by a number from zero to one hundred, so that the highest value is actually 18/100. A value of 18/100 can be thought of as equivalent to 19, and 18/00 (not actually used) is equivalent to 18. Because adventurers of interest tend to be better than average characters, moria stats will average about 13, and are further adjusted by race and class. Some races are just naturally better at being certain classes, as will be shown later. In addition to the more visible stats, each character has certain abilities which are mainly determined by his race, class, and level, but are also modified by his stats. The abilities are fighting, throwing/bows, saving throw, stealth, disarming, magi- cal devices, perception, searching, and infravision. Characters will be assigned an early history, with money and a social class based on that history. Starting money is assigned The Dungeons of Moria Page 2 based on history, charisma, and somewhat upon the average of a character's stats. A character with below average stats will receive extra money to help him survive the first adventure. Each character will also have physical attributes such as race, height, weight, sex, and a physical description. None of these, except weight, play any part in the game other than to give the player a "feeling" for his character. Weight is used for comput- ing carrying capacity and also for bashing. Finally, each character is assigned hit points based on their race, class, and constitution. Spell casters will also receive mana which is expended when casting spells. Mana is based on Wisdom for Priests and Intelligence for Mages. 2.1. Character Stats Strength Strength is important in fighting with weapons and hand to hand combat. A high strength can improve your chances of hitting, and the amount of damage done with each hit. Char- acters with low strengths may receive penalties. Strength is also useful in tunneling, body and shield bashing, and in carrying heavy items. Intelligence Intelligence is the prime stat of a mage, or magician. A high intelligence increases a mage's chances of learning spells, and it also increases the amount of mana a mage has. No spell may be learned by mages with intelligences under 8. Intelligence also modifies a character's chance of disarming traps, picking locks, and using magic devices. Wisdom Wisdom is the prime stat of a priest. A high wisdom increases the chance of receiving new spells from a priest's deity, and it also increases the amount of mana a priest has. No spell may be learned by priests with wisdom under 8. Wisdom also modifies a character's chance of resisting magical spells cast upon his person. Dexterity Dexterity is a combination of agility and quickness. A high dexterity may allow a character to get multiple blows with lighter weapons, thus greatly increasing his kill power, and may increase his chances of hitting with any weapon and dodging blows from enemies. Dexterity is also useful in picking locks, disarming traps, and protecting yourself from pick pockets. Constitution Constitution is a character's ability to resist damage to his body, and to recover from damage received. Therefore a The Dungeons of Moria Page 3 character with a high constitution will receive more hit points, and be more resistant to poisons. Charisma Charisma represents a character's personality, as well as physical looks. A character with a high charisma will receive better prices from store owners, whereas a character with a very low charisma will be robbed blind. A high charisma will also mean more starting money for the charac- ter. 2.2. Character Sex You may choose to be either a male or a female character. Only height and weight are affected by a character's sex. Female characters tend to be somewhat smaller and lighter than their male counterparts. No adjustments to stats or abilities are made because of the sex of a character. Female characters start out with slightly more money than male characters to help offset the weight penalty. 2.3. Character Abilities Characters possess nine different abilities which can help them to survive. The starting abilities of a character are based upon race and class. Abilities may be adjusted by high or low stats, and may increase with the level of the character. Fighting Fighting is the ability to hit and do damage with weapons or fists. Normally a character gets a single blow from any weapon, but if his dexterity and strength are high enough, he may receive more blows per round with lighter weapons. Strength and dexterity both modify the ability to hit an opponent. This skill increases with the level of the char- acter. Throwing/Bows Using ranged missile weapons and throwing objects is included in this skill. Different stats apply to different weapons, but this ability may modify the distance an object is thrown/fired, the amount of damage done, and the ability to hit a creature. This skill increases with the level of the character. Saving Throw A Saving Throw is the ability of a character to resist the effects of a spell cast on him by another person/creature. This does not include spells cast on the player by his own stupidity, such as quaffing a nasty potion. This ability increases with the level of the character, but then most high level creatures are better at casting spells, so it The Dungeons of Moria Page 4 tends to even out. A high wisdom also increases this abil- ity. Stealth The ability to move silently about is very useful. Charac- ters with good stealth can usually surprise their opponents, gaining the first blow. Also, creatures may fail to notice a stealthy character entirely, allowing a player to avoid certain fights. This skill is based entirely upon race and class, and will never improve unless magically enhanced. Disarming Disarming is the ability to remove traps (safely), and includes picking locks on traps and doors. A successful disarming will gain the character some experience. A trap must be found before it can be disarmed. Dexterity and intelligence both modify the ability to disarm, and this ability increases with the level of the character. Using Magical Devices Using a magical device such as a wand or staff requires experience and knowledge. Spell users such as mages and priests are therefore much better at using a magical device than say a warrior. This skill is modified by intelligence, and increases with the level of the character. Perception Perception is the ability to notice something without actively seeking it out. This skill is based entirely upon race and class, and will never improve unless magically enhanced. Searching To search is to actively look for secret doors, floor traps, and traps on chests. Rogues are the best at searching, but mages, rangers, and priests are also good at it. This skill is based entirely upon race and class, and will never improve unless magically enhanced. Infravision Infravision is the ability to see heat sources. Since most of the dungeon is cool or cold, infravision will not allow the player to see walls and objects. Infravision will allow a character to see any warm-blooded creatures up to a cer- tain distance. This ability works equally well with or without a light source. The majority of moria's creatures are cold-blooded, and will not be detected unless lit up by a light source. All non-human races have innate infravision ability. Humans can gain infravision only if it is magi- cally enhanced. The Dungeons of Moria Page 5 2.4. Choosing A Race There are eight different races that you can choose from in moria. Some races are restricted as to what profession they may be, and each race has its own adjustments to a character's stats and abilities. Human The human is the base character, all other races are com- pared to him. Humans can choose any class, and are average at everything. Humans tend to go up levels faster than any other race, because of their shorter life spans. No racial adjustments occur to characters choosing human. Half-Elf Half-elves tend to be smarter and faster than a human, but not as strong. Half-elves are slightly better at searching, disarming, perception, stealth, and magic, but they are not as good at hand weapons. Half-elves may choose any class. Elf Elves are better magicians then humans, but not as good at fighting. They tend to be smarter and faster than either humans or half-elves, and also have better wisdom. Elves are better at searching, disarming, perception, stealth, and magic, but they are not as good at hand weapons. Elves may choose any class except Paladin. Halfling Halflings, or Hobbits, are very good at bows, throwing, and have good saving throws. They also are very good at search- ing, disarming, perception, and stealth; so they make excel- lent thieves (but prefer to be called burglars...). They will be much weaker than humans, and no good at bashing. Halflings have fair infravision, so they can detect warm creatures at a distance. Halflings can choose between being a warrior, mage, or rogue. Gnome Gnomes are smaller than dwarfs, but larger than halflings. They, like the halflings, live in the earth in burrow-like homes. Gnomes are practical jokers, so if they can kill something in a humorous way, so much the better. Gnomes make excellent mages, and have very good saving throws. They are good at searching, disarming, perception, and stealth. They have lower strength than humans so they are not very good at fighting with hand weapons. Gnomes have fair infravision, so they can detect warm creatures at a distance. A gnome may choose between being a warrior, mage, priest, or rogue. Dwarf Dwarves are the headstrong miners and fighters of legend. Since dungeons are the natural home of a dwarf, they are The Dungeons of Moria Page 6 excellent choices for a warrior or priest. Dwarves tend to be stronger and have higher constitutions, but are slower and less intelligent than humans. Because they are so head- strong and are somewhat wise, they resist spells which are cast on them. Dwarves also have good infravision because they live underground. They do have one big drawback though. Dwarves are loudmouthed and proud, singing in loud voices, arguing with themselves for no good reason, scream- ing out challenges at imagined foes. In other words, dwarves have a miserable stealth. Half-Orc Half-Orcs make excellent warriors, and decent priests, but are terrible at magic. They are as bad as dwarves at stealth, and horrible at searching, disarming, and percep- tion. Half-Orcs are, let's face it, ugly. They tend to pay more for goods in town. Half-Orcs do make good priests and rogues, for the simple reason that Half-Orcs tend to have great constitutions and lots of hit points. Half-Troll Half-Trolls are incredibly strong, and have the highest hit points of any character race. They are also very stupid and slow. They will make great warriors and iffy priests. They are bad at searching, disarming, perception, and stealth. They are so ugly that a Half-Orc grimaces in their presence. They also happen to be fun to run... 2.4.1. Race Versus Skills and Stats Stat, hit dice, and experience points per level modifications due to race are listed in the following table. Str Int Wis Dex Con Chr Hit Dice Rqd Exp/level Human 0 0 0 0 0 0 10 +0% Half-Elf -1 +1 0 +1 -1 +1 9 +10% Elf -1 +2 +1 +1 -2 +1 8 +20% Halfling -2 +2 +1 +3 +1 +1 6 +10% Gnome -1 +2 0 +2 +1 -2 7 +25% Dwarf +2 -3 +1 -2 +2 -3 9 +20% Half-Orc +2 -1 0 0 +1 -4 10 +10% Half-Troll +4 -4 -2 -4 +3 -6 12 +20% Racial abilities as compared to each other, with 1 the lowest, or worst, and 10 the highest, or best, are listed in the following table. The Dungeons of Moria Page 7 Disarm Search Stealth Percep Fight Bows Save Infra Human 5 5 5 5 5 5 5 None Half-Elf 6 7 7 6 4 6 6 20 feet Elf 8 9 7 7 3 9 7 30 feet Halfling 10 10 10 10 1 10 10 40 feet Gnome 9 7 9 9 2 8 9 30 feet Dwarf 6 8 3 5 9 5 8 50 feet Half-Orc 3 5 3 2 8 3 3 30 feet Half-Troll 1 1 1 1 10 1 1 30 feet 2.5. Choosing A Class Once a race has been chosen, you will need to pick a class. Some classes will not be available to certain races, for instance, a Half-Troll cannot become a Paladin. For the first few adventures it is suggested that you run a warrior or rogue. Spell casting generally requires a more experienced player that is familiar with survival techniques. Warrior A Warrior is a hack-and-slash character, who solves most of his problems by cutting them to pieces, but will occasion- ally fall back on the help of a magical device. His prime stats are Strength and Constitution, and a good Dexterity can really help at times. A Warrior will be good at Fight- ing and Throwing/Bows, but bad at most other skills. Mage A Mage must live by his wits. He cannot hope to simply hack his way through the dungeon, and so must therefore use his magic to defeat, deceive, confuse, and escape. A mage is not really complete without an assortment of magical devices to use in addition to his spells. He can master the higher level magical devices far easier than anyone else, and has the best saving throw to resist effects of spells cast at him. Intelligence and Dexterity are his primary stats. There is no rule that says a mage cannot become a good fighter, but spells are his true realm. Priest A Priest is a character of holy devotion. He explores the dungeon only to destroy the evil that lurks within, and if treasure just happens to fall into his pack, well, so much more to the glory of his temple! A priest receives his spells from a deity, and therefore does not choose which spells he will learn. He is familiar with magical devices, preferring to call them instruments of god, but Is not as good as a mage in their use. Priests have good saving throws, and make decent fighters, preferring blunt weapons over edged ones. Wisdom and Charisma are the priest's The Dungeons of Moria Page 8 primary stats. Rogue A Rogue is a character that prefers to live by his cunning, but is capable of fighting his way out of a tight spot. He is the master of traps and locks, no device being impossible for him to overcome. A rogue has a high stealth allowing him to sneak around many creatures without having to fight, or sneak up and get the first blow. A rogue's perception is higher than any other class, and many times he will notice a trap or secret door before having to search. A rogue is better than a warrior or paladin with magical devices, but still can not rely on their performance. Rogues can also learn a few spells, but not the powerful offensive spells mages can use. A rogue's primary stats are Intelligence and Dexterity. Ranger A Ranger is a warrior/mage. He is a good fighter, and the best of the classes with a missile weapon such as a bow. The ranger learns spells much more slowly than a mage, but is capable of learning all but the most powerful spell. Because a ranger is really a dual class character, more experience is required for him to advance. A ranger has a good stealth, good perception, good searching, a good saving throw, and is good with magical devices. His primary stats are Intelligence and Dexterity. Paladin A Paladin is a warrior/priest. He is a very good fighter, second only to the warrior class, but not very good at mis- sile weapons. He receives prayers at a slower pace then the priest, but can eventually learn all the prayers. Because a paladin is really a dual class character, it requires more experience to advance him. A paladin lacks much in the way of abilities. He is poor at stealth, perception, searching, and magical devices. He has a decent saving throw due to his divine alliance. His primary stats are Strength and Charisma. 2.5.1. Race Versus Class The Dungeons of Moria Page 9 Warrior Mage Priest Rogue Ranger Paladin Human Yes Yes Yes Yes Yes Yes Half-Elf Yes Yes Yes Yes Yes Yes Elf Yes Yes Yes Yes Yes No Halfling Yes Yes No Yes No No Gnome Yes Yes Yes Yes No No Dwarf Yes No Yes No No No Half-Orc Yes No Yes Yes No No Half-Troll Yes No Yes No No No 2.5.2. Class Versus Skills Class abilities as compared to each other, with 1 as the lowest, or worst, and 10 as the highest, or best are shown in the follow- ing table. Save Stea- Magic Extra Fight Bows Throw lth Disarm Device Percep Search Exp/lev Warrior 10 6 3 2 4 3 2 2 +0% Mage 2 1 10 5 6 10 8 5 +30% Priest 4 3 6 5 3 8 4 4 +20% Rogue 8 9 7 10 10 6 10 10 +0% Ranger 6 10 8 7 6 7 6 6 +40% Paladin 9 5 4 2 2 4 2 2 +35% 3. Adventuring After you have created your character, you will begin your moria adventure. Symbols appearing on your screen will represent the dungeon's walls, floor, objects, features, and creatures lurking about. In order to direct your character through his adventure, you will enter single character commands. Moria symbols and commands each have a help section devoted to them. You should review these sections before attempting an adventure. Finally, a description of the town level and some general help on adventuring are included. 4. Symbols On Your Map Symbols on your map can be broken down into three categories: Features of the dungeon such as walls, floor, doors, and traps; objects which can be picked up such as treasure, weapons, magical devices, etc; and creatures which may or may not move about the dungeon, but are mostly harmful to your character's well-being. The Dungeons of Moria Page 10 Some symbols can be in more than one category. Also note that treasure may be embedded in a wall, and the wall must be removed before the treasure can be picked up. It will not be necessary to remember all of the symbols and their meanings. A simple command, the `/', will identify any character appearing on your map. See the section on commands for further help. Features . A floor space, or hidden trap 1 Entrance to General Store # A wall 2 Entrance to Armory ' An open door 3 Entrance to Weapon Smith + A closed door 4 Entrance to Temple ^ A trap 5 Entrance to Alchemy Shop < A staircase up 6 Entrance to Magic Shop > A staircase down : Obstructing rubble ; A loose floor stone An open pit (Blank) % A mineral vein @ The character Objects ! A flask or potion ? A scroll " An amulet [ Hard armor $ Money (Can be embedded) \ A hafted weapon & A chest ] Misc. armor ( Soft armor _ A staff ) A shield { Missile (arrow, bolt, pebble) * Gems (Can be embedded) | Sword or dagger - A wand } Missile arm (Bow, X-bow, sling) / A pole-arm ~ Misc = A ring , Food s A skeleton The Dungeons of Moria Page 11 Creatures a Giant Ant A Giant Ant Lion b Giant Bat B The Balrog c Giant Centipede C Gelatinous Cube d Dragon D Ancient Dragon e Floating Eye E Elemental f Giant Frog F Fly g Golem G Ghost h Harpy H Hobgoblin i Icky-Thing I j Jackal J Jelly k Kobold K Killer Beetle l Giant Louse L Lich m Mold M Mummy n Naga N o Orc or Ogre O Ooze p Human(oid) P Giant Human(oid) q Quasit Q Quylthulg r Rodent R Reptile s Skeleton S Scorpion t Giant Tick T Troll u U Umber Hulk v V Vampire w Worm or Worm Mass W Wight or Wraith x X Xorn y Yeek Y Yeti z Zombie Z $ Creeping Coins , Mushroom Patch 5. Commands All commands are entered by pressing a single key. Some commands are capital or control characters, which require you to hold down the shift or control key while pressing another key. As a spe- cial feature, control keys may be entered in a single stroke, or in two strokes, with a `^' character first. There are two command sets: the original command set which is the default, and the rogue like command set. The rogue like command is generally more convenient, especially if you don't have a keypad. The following tables summarize the two command sets. Certain commands may be preceded by an optional count, and certain com- mands must be followed by a direction. These conditions are indicated in the tables by `@' for an optional count, and `~' for a direction. If a particular command requires additional key strokes, then they will be prompted for. The Dungeons of Moria Page 12 Original command summary. a Aim and fire a wand @ B ~ Bash (object/creature) b Browse a book C Change name c ~ Close a door @ D ~ Disarm a trap/chest d Drop an item E Eat some food e Equipment list F Fill lamp with oil f Fire/Throw an item G Gain new magic spells i Inventory list L Locate with map @ j ~ Jam a door with spike M Map shown reduced size l ~ Look given direction @ R Rest for a period m Magic spell casting S Search Mode @ o ~ Open a door/chest @ T ~ Tunnel in a direction p Pray V View scoreboard q Quaff a potion = Set options r Read a scroll ? Command quick reference @ s Search for trap or door { Inscribe an object t Take off an item @ - ~ Move without pickup u Use a staff . ~ Run in direction v Version, credits and manual / Identify a character w Wear/Wield an item CTRL-K Quit the game x Exchange weapon @ CTRL-P Repeat the last message < Go up an up staircase CTRL-X Save character and quit > Go down a down staircase @ ~ for movement Rogue like command summary. c ~ Close a door C Character description d Drop an item @ D ~ Disarm a trap/chest e Equipment list E Eat some food @ f ~ Force/bash item/monster F Fill lamp with oil i Inventory list G Gain new magic spells m magic spell casting M Map shown reduced size @ o ~ Open a door/chest P Peruse a book p Pray Q Quit the game q Quaff a potion @ R Rest for a period r Read a scroll @ S ~ Spike a door @ s Search for trap or door T Take off an item t Throw an item V View scores v Version, and manual W Where: locate self w Wear/Wield an item X Exchange weapon x ~ Examine surroundings Z Zap a staff z Zap a wand # Search Mode = Set options < Go up an up staircase / Identify a character > Go down a down stair @ CTRL-P Previous message review { Inscribe an object @ - ~ Move without pickup ? Type this page @ CTRL ~ Tunnel in a direction CTRL-X Save game and exit @ SHFT ~ Run in direction @ ~ for movement The Dungeons of Moria Page 13 5.1. Special keys. Certain commands may be entered at any time input is accepted. The special character control-R, entered as a single key stroke, will always refresh the screen. This may be used at any prompt for input, and is otherwise ignored. If you are playing on a UNIX or similar system, then there are some additional special characters used by moria. The special character control-C will interrupt moria, and ask if you really want to die and quit the game. If you choose not to die, moria merely continues as before, except that resting, running, repeated commands, etc will be terminated. You can suspend the game with control-Z, and return to the original command shell. In this case, moria is not terminated, and may be restarted at any time from the shell. Alternatively, the special command `!' is available to run any normal shell command. When it is com- plete, moria will restart. For many input requests or queries, the special character ESCAPE will abort the command. For the "-more-" message prompts, any of SPACE, ESCAPE, RETURN (control-m), or LINEFEED (control-j) can be used to continue after pausing to read the displayed message. It is possible to give control character commands in two key stroke, by typing a `^' followed by the appropriate letter of the alphabet. This is useful when running moria in circumstances where control characters are intercepted by some external pro- cess, or by the operating system. 5.2. Direction. For the original style command set, a direction is given by a digit which is in the appropriate orientation on your keypad. For the rogue like command set, a direction is given by one of the letters `hykulnjb'. Again, the relative position of the keys on the keyboard gives a clue as to the direction. The digit `5' for the original commands, and the period `.' for rogue like com- mands, is a null direction indicator. This is only allowed in a movement command (to stay in one place) or in a look command (to look in all directions). Original Directions | / 7 8 9 - 4 6 - 1 2 3 / | The Dungeons of Moria Page 14 Rogue-like Directions | / y k u - h l - b j n / | Movement is accomplished by specifying a direction immediately. Simply press the appropriate key and you character will move one step in that direction. You can only move onto and through floor spots, and only if they contain no creatures or obstructing objects such as a closed door. Other commands that require a direction will prompt for it. Moving your character one step at a time can be time consuming and boring, so a faster method has been supplied. For the origi- nal style command set, by using the Run command `.', you may move in a direction until something interesting happens. For instance, by pressing the period key `.' followed by the direc- tion 8, your character would continue to move up the screen, only coming to a stop after at least one condition is satisfied. For the rogue like command set, typing a shifted directional letter will move you in that direction until something interesting hap- pens. The stopping conditions are described more completely in the run command description below. 5.3. Command counts. Some commands can be executed a fixed number of times by preced- ing them with a count. Counted commands will execute until the count expires, or until you type any character, or until some- thing significant happens, such as being attacked. Thus, a counted command doesn't work to attack another creature. While the command is being repeated, the number of times left to be repeated will flash by on the command line at the bottom of the screen. To give a count to a command in the rogue like mode, type the number in digits, then the command. A count of zero defaults to a count of 99. To give a count to a command in the original mode, type a `#', followed by the digits. To count a movement command (which is itself a digit), type a space after the number, and you will then be prompted for the command. Counted commands are very useful for searching or tunneling, as The Dungeons of Moria Page 15 they automatically terminate on success, or if you are attacked. You may also terminate a counted command, or a Run command, by typing any character. This character is ignored, but it is safest to use a SPACE or ESCAPE which are always ignored as com- mands. 5.4. Selection of objects. Many commands will also prompt for a particular object to be used. For example, the command to read a scroll will ask you which of the scrolls that you are carrying that you wish to read. In such cases, the selection is made by typing a letter of the alphabet; if you are selecting from your pack, you may also type a digit to select the item whose inscription is that digit. The prompt will indicate the possible letters, and will also allow you to type the key `*', which causes all of the available options to be described. The particular object may be selected by an upper case or a lower case letter. If lower case or a digit is used, the selection takes place immediately. If upper case is used, then the partic- ular option is described, and you are given the option of con- firming or retracting that choice. Upper case selection is thus safer, but requires an extra key stroke. 5.5. Command descriptions In the following command descriptions, the original style key is given. If the rogue like key for that command is different, then it will be shown inside the braces following the command name. B - Bash. {f - force} The bash command includes breaking open doors and chests, or bashing an opponent. Your bashing ability increases with weight and strength. In addition, when bashing an opponent, you will either perform a body bash, or, if wielding a shield, perform a shield bash which is more effective. Bashing a door can throw you off balance, but this will not generally be a problem. Doors that have been jammed closed with spikes can only be opened by bashing. Locked doors may also be bashed open. Bashing a door open will permanently break it. Bashing a creature affects both you and the opponent. Depending on your dexterity, you may or may not be thrown off balance allowing free moves to your opponent. If the bash is successful, your opponent may be thrown off balance, thus giving you some free hits or a chance to run. Huge creatures such as ancient dragons will be difficult or impossible to bash successfully. The Dungeons of Moria Page 16 A player automatically performs a shield bash instead of a body bash, if he is currently wearing a shield. A shield bash adds the damage of a shield to that of the bash, so it is more effective. Size and material both affect the damage that a shield will do. You can apply a count to this command, but if you are thrown off balance, the count will be reset straight away. C - Print character (to screen or file). This command allows the player to either display his charac- ter on the terminal screen, or to print an entire character info listing to a file. The character's history, equipment, and inventory list are also included if you chose to print it to a file. D - Disarm a trap. You can attempt to disarm floor traps, or trapped chests. If you fail to disarm a trap, there is a chance that you blunder and set it off. You can only disarm a trap on a chest after finding it with the search command. This com- mand can have a count. E - Eat some food. A character must eat occasionally to remain effective. As a character grows hungry, a message will appear at the bottom of the screen saying "Hungry". If a character remains hungry long enough, he will become weak, eventually start fainting, and finally die of starvation. F - Fill a lamp or lantern with oil. If your character is currently using a lamp for light, and if he has a flask of oil in inventory, he may refill the lamp by using this command. A lamp is capable of a maximum of 15000 turns of light, and each flask has 7500 turns of oil contained in it. G - Gain new spells. To actually learn new spells, you must use this command. When you are able to learn some spells, the word "Study" will appear on the status line at the bottom of the screen. Mages, rogues, and rangers must have the magic books con- taining new spells to be able to learn them. Priests and Paladins are given their prayers by their gods, and hence do not need a holy book before learning the prayers in it. They do need the book in order to use the prayers. L - Location on map. {W - where} The location command allows you to look at all parts of the current dungeon level. The displayed view of the dungeon is shifted to bring your current position as close to the center as possible. You may then shift the displayed map in any of the eight possible directions. Each shift moves your view point by one half screen. The top line displays a map The Dungeons of Moria Page 17 section number, each map section having a height and width one half that of the display, and indicates the direction of the display from your current position. If you exit this command while you are not on the display, then the display is centered again. M - Map shown reduced size. This command will show the entire map, reduced by a factor of nine, on the screen. Since nine places map into every character on the screen, only the major dungeon features will be visible. This is especially useful for finding where the stairs are in relation to your current position. It is also useful for identifying unexplored areas. R - Rest for a number of turns. You may rest one turn with the null movement command. Rest- ing for longer periods of time is accomplished by using the Rest command, followed by the number of turns you want to rest your character. Resting will continue until the speci- fied duration has expired, or something to wake the charac- ter happens, such as a creature wandering by, or getting hungry, or some disability like blindness expiring. It is sometimes a good idea to rest a beat-up character until he regains some of his hit points, but be sure to have plenty of food if you rest often. If you have accidentally entered in a rest period too large, or change your mind about the resting period, you may wake your character up by typing any character. Space is best, since if the rest ends just before the character is typed, the space is ignored as a command. It is also possible to rest by typing the count first, and using either the Rest or the null movement command. If you type `*' for the rest count, your character will rest until both hp and mana reach their maximum values. As above, you will immediately stop resting if anything interesting happens. S - Search mode toggle. {#} The Searching toggle will take you into and out of search mode. When first pressed, the message "Searching" will appear at the bottom of the screen. You are now taking two turns for each command, one for the command and one turn to search. This means that you are taking twice the time to move about the dungeon, and therefore twice the food. If a creature should happen by or attack you, search mode will automatically shut off. You may also turn off search mode by again pressing the `S' {or #} key. T - Tunnel through rock. {control-} Tunneling (Mining) is a very useful art. There are four kinds of rock present in the dungeons of moria: Permanent moria-5.6.debian.1/doc/faq0000644000175000017500000007530111074752623013437 0ustar pjbpjbFrequently Asked Questions for rec.games.roguelike.moria Last changes: 6/7/06: (Bug fix for compiling on 64-bit systems) 4/21/05 (Color Moria for PC no longer available) 2/7/05 (Mac OS X Moria available) First, a general guideline for posters. When you post any question related to playing or debugging the game, please give the version number, which you can get during the game by pressing "v". These are the questions in the Moria Frequently Asked Questions list. Quick answers to some questions are given in parentheses; more detailed answers to those questions with numbers are in the list which follows. The answers below are separated by form feeds, so that in most news readers, you can get the answer you want without looking at the rest of the spoilers. (Search for the string "Q5", for example.) Many of the answers are only correct for Umoria versions (4.87 and 5.x); I don't know much about the other versions of Moria. Please send any corrections or other suggested questions to me at grabiner@alumni.princeton.edu The FAQ is now maintained on the Web at A copy of the FAQ as it was last posted may be obtained by FTP from the RTFM archive, ftp://rtfm.mit.edu/pub/usenet/rec.games.roguelike.moria/rec.games.roguelike.moria_Frequently_Asked_Questions or by using the mailserver on RTFM. To use the mailserver, send a message to mail-server@rtfm.mit.edu containing the line "send /pub/usenet/rec.games.roguelike.moria/rec.games.roguelike.moria_Frequently_Asked_Questions" There is also a WWW page for Moria, with links to the spoilers, newsgroup, this FAQ, and the FTP site. It is The most common questions, asked by both beginners and others: Q1. How do I get the Moria sources/executables/documentation? (PC executables are available at , Linux source is available at . FreeBSD Moria is at . Sources and other executables are on the main archive at .) Q2. I can't get Moria/Angband set up on my machine; is there a server on another machine that I can use? (Yes; telnet://chungkuo.org) What does this item do? (Answer is below with the spoilers.) Why do most winning characters carry several copies of spell books? (In case one gets stolen.) What does the (-2) in Chain Mail (-2) [14,+2] mean? (It's a penalty to hit, caused by the heavy armor.) Q3. How do I use wizard mode, and what can I do in it? (In 5.x, just type control-W.) Non-spoiler questions: Q4. How does resistance work? Are two items of resistance cumulative? (Not if both are worn items.) Q5. How does speed work? Do you get faster if you are already Very Fast and get another speed item? (Yes.) Q6. I'm playing Moria version V; how does that compare to the current version? Is it compatible? Q7. I think I've found a bug; what should I do? (Check that it isn't already known, then report it with the version number and system.) Common spoiler requests: Q8. What are the special abilities of ego weapons? Crowns? Amulet of the Magi? Cloak of Protection? Q9. How much damage do spells and wands do? Q10. What does spell Y do? Q11. On what level do you find X? (Level 25 is best for gain stat potions.) Q12. How many attacks can I get with this weapon? Q13. How do you kill an ancient multi-hued dragon? (Usually, you don't.) Q14. How do you kill an emperor lich? (With speed and spells.) Q15. What is the grape jelly trick? Does it work in Umoria 5.x? (No.) Questions related to the source code: Q16. I don't like haggling; can I change the source code to turn it off? Q17. How do you create objects in wizard mode? Q1. How do I get the Moria sources/executables/documentation? A working version of UMoria 5.5.2 is now available for the PC; it's also available at the main Moria archive, but this URL is more likely to work. http://www3.ns.sympatico.ca/dmswaine/m552-386.zip A version with a few additional features is available at: http://www.geocities.com/lhelgeland/umoria.html Linux sources (designed for Debian, but they also work on Red Hat at least) are at http://packages.debian.org/moria Sources for FreeBSD are at http://www.freebsd.org/cgi/ports.cgi?query=Moria&stype=all. UMoria 5.5.2 is available for Mac OS X (search for "Moria") http://fink.sourceforge.net Umoria 5.5.2 has been ported to the PalmOS at http://roguelike-palm.sourceforge.net/kMoria/index.php The main Moria archive has moved to a new home; it makes files available by anoymous FTP: ftp://ftp.greyhelm.com/pub/Games/Moria Three near-complete mirrors are available. ftp://ftp.funet.fi/pub/unix/games/moria/ ftp://ftp.planetmirror.com/pub/roguelike/moria/ (in Australia) (The third is a slow connection; please do not use it if you can get to another site.) http://www.piratehaven.org/~beej/moria/mirror/Games/Moria/ Use the pathnames listed below, ignoring the leading /pub/Games/Moria. Some files on the mirrors may be compressed with different compression programs such as gzip. The documentation, including the official manual and this FAQ, is available at http://www2.ecst.csuchico.edu/~beej/moria/ The sources for Umoria 5.5.0 were also posted to comp.sources.games, so they should be available (in compressed shar form) on any site which archives comp.sources.games, such as ftp.uu.net. The following paths give the structure of the Moria archive; they will probably be maintained when the archive moves somewhere else. /pub/Games/Moria/[machine name] Executables for the Amiga, Atari ST, IBM PC, and Mac; look at the README files in these directories for more information. Some of these files may need to be transferred in binary mode; type "binary" before transferring the files. KSU has both color and monochrome executables for the IBM PC. European users can also get Mac binaries from jyu.fi, in a file /maclib/game/moria.sit.bin. /pub/Games/Moria/pc/80386-5.5.2/m552-386.zip This is the 5.5.2 executable for the PC. /pub/Games/Moria/source/um5.5.2.tar.Z A compressed tar file containing the entire source, for use on any system; if you have tar on your system, this is probably the file that you want. (If you don't have compress, you can FTP it as well; it is /pub/Games/Moria/compress.tar.) This file must be transferred in binary mode; type "binary" before getting the file. Once you have the tar.Z file, type "zcat um5.5.2.tar.Z | tar xf -" to extract the files, and read the README files for help in installing. /pub/Games/Moria/pc/zip-arc/mor55src.zip A ZIP file containing the source. /pub/Games/Moria/pc/zip-arc/wmoria10.zip_exec /pub/Games/Moria/pc/zip-arc/wmoria10.zip_source Source and Modula-2 executables for Wmoria 1.0, a port of Umoria 5.5.0 to Windows 3.1. /pub/Games/Moria/patches Patches for upgrading Moria from one version the the next version, and for modifications. /pub/Games/Moria/XMoria/xm1.07.tar.Z The source to Moria for X Windows. /pub/Games/Moria/doc The documentation for Moria 5.5, including the official documentation, the FAQ file, and a complete monster list. /pub/Games/Moria/pc/mono5.5 The auxilliary files are in this directory; you may need them if you have an executable without them. /pub/Games/Angband The source to Angband for UNIX, and source and executable for the PC and Mac. /pub/Games/Moria/boss The source distribution, in Pascal, for BOSS. /pub/Games/Moria/vms The source discribution, in Pascal, for VMS Moria 4.8 and 5.0. Umoria 5.x will also work on VMS machines. (Note that VMS Moria 5.0 is not a version of Umoria 5.x.) /pub/Games/Moria/unofficial Other unofficial modifications of Moria, including JAMoria, the druid version for the PC, and the sources for Morgul and Pmoria. /pub/Games/Moria/utils/calchits.shar.Z A program for calculating the average damage done with various weapons, allowing you to compare them. VMS sources for Imoria are available on ubvms.cc.buffalo.edu, in a directory /maslib/games/imoria. VMS Moria 4.8 and 5.0 sources are also there. Linux code for Imoria is available from http://www.angelfire.com/games3/imoria/imoria.html. Q2. I can't get Moria/Angband set up on my machine; is there a server on another machine that I can use? (Yes; telnet://chungkuo.org) There is a BBS at telnet://chungkuo.org which has Moria and many other Roguelike games. Telnet to this site, or see the Web page http://chungkuo.50megs.com/gnet.html for more information. Note that the standard telnet client in Windows is buggy, and will cause problems with this BBS. The maintainer of the BBS recommends Mtelnet and makes it available on the Web page. Q3. How do I use wizard mode, and what can I do in it? In Umoria 5.x, anyone can use wizard mode by typing ^W. However, characters who play in wizard mode are permanently barred from the scoreboard; wizard mode should be used only for debugging and experimenting. In 4.87 on Unix systems, only the person who installed the game can use wizard mode; if you are the installer, the passwords are in the source file constants.h. In PC-Moria 4.8x, you need to know the passwords to use wizard mode, and the password will depend on who compiled your game. 4.87 has both wizard and god modes; 5.x's wizard mode is equivalent to the old god mode. The 4.87 wizard mode allows you to do only things related to the game (cure all problems, teleport, identify). The 5.x wizard mode and 4.87 god mode allow you to test the program by editing your character, creating objects, deleting monsters, and similar things. In wizard mode, ^H or DELETE will give you a list of the available commands. Q4. How does resistance work? Are two items of resistance cumulative? Resist heat/cold potions and spells give temporary resistance to heat or cold. All other resistance items give permanent resistance. Two permanent resistances are not cumulative, and two temporary resistances are cumulative only in duration. Fire and cold do 1/3 damage if you have single resistance, 1/9 if you have double. Acid does 1/2 damage if you have any armor to corrode, 1/3 if you have resistance but no armor, and 1/4 if you have resistance and armor. Lightning does 1/3 damage if you have resistance. There is no resistance against poison gas. Q5. How does speed work? Do you get faster if you are already Very Fast and get another speed item? Very Fast is the highest speed that can be displayed, but if you are fortunate enough to find several speed items, you can get still faster. Permanent speed items (rings and boots) are cumulative, and temporary speed (potions, spells, and staffs) can add one more point to your speed. Multiple uses of temporary speed are cumulative only in duration. Q6. I'm playing Moria version V; how does that compare to the current version? Is it compatible? Moria versions: Umoria 5.5.2: This is the current version of Umoria. It will accept characters from all Umoria 5.x versions. Umoria 5.3.0-5.5.1: These are essentially identical to 5.5.2, and compatible with it, although 5.5.2 fixes a few bugs, and there have been a few minor changes. Upgrading from 5.5.1 to 5.5.2 is probably not necessary; upgrading from earlier versions is recommended. Umoria 5.2.2: This is in good condition, and compatible with the current version. One bug: don't rest more than 10,000 turns in place, and leave the level if you start seeing lots of "Compacting monsters..." messages, or the game may lock up. Umoria 5.2.1: This is playable, but has no high scores file; you probably want to upgrade if possible. Umoria 5.1.0-5.2.0: These versions can be played, but are somewhat buggy. If you run into an invisible, invincible monster which doesn't move or attack, get off the level. If you can FTP the sources or executables, you should upgrade. The U is often omitted from the names of the following Umoria versions. Umoria 4.87/PC-Moria 4.87x: This version is based on the old VMS Moria. It is relatively bug-free, but it doesn't have the features of the 5.x versions, such as monster memory. The save file format is incompatible with 5.x, and several people have failed in attempts to write a conversion program. Umoria 4.85: A moderately buggy version, also based on VMS Moria. Umoria/PC-Moria 4.83: An extremely buggy version, based on VMS Moria. This version is essentially unplayable (see invisible doesn't work, stores all close after 32768 turns, etc.) The following versions are not compatible with Umoria, and Umoria spoiler files may not apply to them. I don't know much about these versions. UB Moria 5.0: Also known as VMS Moria 5.0, this is the current version of VMS Moria. It has more monsters, a Black Market, and other features. Imoria 4.9: This is apparently a very good game, with new character classes and other features. It is now available for VMS and Linux only; it has not yet been ported to DOS or other Unix platforms. Amiga Moria 3.0: Although this version was originally based on 4.85, it has many added monsters, features, and bugs (including items which make you virtually invincible). BOSS: This game changes the setting of Moria, but keeps many of the items. It is based on VMS Moria 5.0. Pmoria: A version of Moria based on 5.5.0, with many enhancements. Morgul: An expanded version of Moria, keeping a similar setting. It is based on Umoria 5.5.0. Angband: Another expanded version of Moria with a similar setting. It is based on Umoria 5.2.1; current versions include some of the bug fixes from later versions. Although the basic game structure is similar to Moria's, there have been many enhancements. For more information, read the USENET group rec.games.roguelike.angband. Q7. I think I've found a bug; what should I do? When you are reporting a suspected bug, make sure to give the version number and the system. The bug report can be posted here or sent to me. If someone else maintains the game on your machine, the bug report should also be sent to him or her; the bug may be in a change on your machine but not in my code. If you have a patch for the bug, it would be best to send the patch by Email, so that I can check the patch before releasing it. If you report a bug which has been fixed in the current version, I may be able to send you a patch, or at least tell you that you can fix the bug by upgrading. If the bug hasn't been fixed, a good bug report may make it easy to fix. The following bugs have been reported with some frequency. Fixes are included where known; for 5.x versions, and 4.8x if you don't have a character you need to preserve, the best fix is to upgrade. All versions are Umoria unless indicated otherwise. All versions compiled with 64-bit compilers (common on Linux): Stores sell items for 4 billion gold pieces. To fix this, edit types.h and change "long" to "int" in the first two typedefs: typedef unsigned int int32u; typedef int int32; All versions: Occasional rooms are created with no exit. The only attempt to fix this bug introduced others and had to be undone. 4.87-5.2.2: The game locks up if you wait in place for about 10,000 turns. This can be fixed in the source; in the function compact_monsters() in misc1.c, change "if (cur_dis > m_ptr.cdis)" to "if (cur_dis < m_ptr.cdis)". If you can't fix the bug, leave the level if you see lots of "Compacting monsters..." messages. 4.87-5.2.1: Your carrying capacity decreases. This cannot be fixed for an individual character without hacking the savefile, or modifying the program to fix the savefile. To avoid it, don't use spikes, and don't fight while wielding arrows in 4.87. 5.1.0-5.2.0: Invisible monsters which don't move or attack are sometimes created. Get off the level if you see one. 4.87: Monsters sometimes chase you in the wrong direction. 4.87: Wands/spells of polymorph and drain life work only when you are adjacent to the monster. 4.85: Several annoying bugs still exist, but this version is at least playable. 4.83: Many bugs. Upgrade. Druid: Potions of Healing can heal you above your maximum hit points. OS/2 Moria: Erick the Honest takes over all the stores eventually, and refuses to stock expensive items. This cannot be fixed by transferring a character from OS/2 to other versions. Amiga Moria 3.0: Some items make you extremely fast (and hungry). Amiga Moria 3.0: The system crashes when you leave the game, because it tries to close the screen without deactivating it. Jump to the workbench screen _instantly_ as the save (or exit) commences via [left amiga + N] and activate the workbench screen via a mouseclick or [alt + left amiga] (the keyboard shortcut for a mouse-click). Q8. What are the special abilities of ego weapons? Crowns? Amulet of the Magi? Cloak of Protection? All version-dependent changes are marked in brackets. Amulet of the Magi free action, see invisible, searching, +3 AC. [no searching bonus in 4.87] Cloak of Protection no special ability, just a larger bonus than usual. Ego weapons: (HA) Holy Avenger +(1-4) str, +(1-4) AC, (SE), (SU), sustain stat, see invisible. (DF) Defender stealth, regeneration, free action, see invisible, feather fall, RF, RC, RL, RA, +(6-10) to AC (SM) Slay Monster Damage (x 2) vs. monsters, see invisible. [found in 4.87 only] (SA) Slay Animal Damage (x 2) vs. animals, [does not exist in 4.87; has see invisible through 5.1.4] (SD) Slay Dragon Damage (x 4) vs. dragons. (SE) Slay Evil Damage (x 2) vs. evil monsters. (SU) Slay Undead Damage (x 3) vs. undead, [see invisible in 5.1.5 and later] (FT) Flame Tongue Damage (x 1.5) vs. monsters harmed by fire. (FB) Frost Brand Damage (x 1.5) vs. monsters harmed by cold. A HA which is +1 to strength sustains strength; +2, intelligence; +3, wisdom; +4, constitution (not dexterity). Crown of the Magi +(1-3) int, (RF), (RC), (RA), (RL) [In 4.87, it had see invisible instead of RL] Crown of Lordliness +(1-3) wis, chr. Crown of Might +(1-3) str, dex, con, free action. Crown of Seeing see invisible, +(10-25) searching. [+(2-5) to seach in 4.87] Crown of Regeneration Regeneration. Crown of Beauty +(1-3) charisma. Regeneration lets you recover mana and hit points at 1.5 times the normal rate, but also makes you use up food much more quickly. Free action prevents you from being slowed or paralyzed by monsters. Q9. How much damage do spells and wands do? Spell Name 4.87 damage 5.1.0 and later damage Magic Missile 2d6 2d6 Stinking Cloud 8 12 Lightning Bolt 3d8 4d8 Lightning Ball 24 32 Frost Bolt 4d8 6d8 Frost/Cold Ball 32 48 Acid Ball 40 60 Fire Bolt 6d8 9d8 Fire Ball 48 72 Wand of Drain Life 50 75 [in 5.1.4 and later] In 5.x only, a wand of wall building will do 4d8 damage to any creature buried in the wall (except one that moves through walls), and will kill any immobile creature. On the creature's next turn, it will attempt to move out of the wall, and if it is unable to do so, it will take 10d8 damage and dig its way out. Everything below is the same in all versions. Wand of Light/Staff of 2d8 (if sensitive) Starlight Stone to Mud 100 (if sensitive) Orb of Draining 3d6 + caster's level, double to evil creatures Dispel Undead/Evil 1-60 from scroll or staff; 1 up to triple caster's level from spell Holy Word Dispel evil for 1 up to quadruple caster's level Notes: All mage spells in 4.87 do the damage listed in the table above if cast from a wand, and 1 point more if cast by a mage. All ball spells do full damage for a direct hit, half damage one space away, and 1/3 damage two spaces away. Q10. What does spell Y do? Non-obvious spell effects: Mage spells: Phase Door: short-range teleport. Find Hidden Traps/Doors: also detects stairs. Sleep I: sleep one monster in a given direction. Recharge Item I: fewer charges than Recharge Item II, and more likely to fail. Sleep II: sleep all monsters adjacent to player. Sleep III: sleep all monsters with a line of sight to player (including invisible ones). Word of Destruction: obliterates everything within 15 spaces of the player; Balrog will teleport to another level. Priest spells: Bless: +2 to AC, and +5 to chance to hit (equivalent to +1-2/3 bonus on weapon) for a short time. Blind Creature: blinded creatures wander around confused until they recover. Portal: medium-range teleport. Chant: double duration Bless. Sanctuary: sleep creatures adjacent to player. Protection from Evil: prevents any evil creature of the player's level or lower from attacking the player. Earthquake: causes random walls and ceilings in the area to collapse, possibly injuring anything nearby. Turn Undead: all undead of the player's level or lower, and some of higher level, will attempt to flee [in 5.5.0 and earlier versions, they will be confused] Prayer: quadruple duration Bless. Dispel Undead/Evil: affects all undead/evil within line of sight (even invisble ones in 5.x versions), damage is from 1 up to 3x player's level, 1-60 from scroll or staff. Glyph of Warding: creates a glyph which monsters cannot enter, but have a small chance of breaking. Holy Word: heals player completely, cures poison and fear, and dispels evil for 1 to 4x player's level. [In 5.5.1 and later versions, also restores all stats, and makes player invulnerable for 3 turns.] Q11. On what level do you find X? Where important objects are found: In 4.87, 1/20 of items are chosen as if you were on level 50. In 5.1 and all later versions, 1/12 of items are chosen as if you were on a deeper level, which has (current level/50) chance of being level 50; this check is not made in town. This affects only the type of item, not its enchantment. Items become somewhat less common as you go deeper than the indicated levels; however, if you can survive down there, this is compensated for by the fact that there are more treasures on deeper levels. Item type Level Ego weapons, special armor, Progressively more common as you get boots, gloves, helmets deeper, all the way to level 55 Healing potion 12 Gain stat potions 25 Restore mana potion 25 Invulnerability potion 40 Gain experience potion 50 Genocide scroll 35 Destruction scroll 40 Rune of Protection scroll 50 Mass Genocide scroll 50 Amulets of wisdom, charisma 20 Gain str/int/dex/con rings 30 Amulet of the magi 50 Ring of speed 50 Staff of speed 40 Staff of mass polymorph 46 Staff of dispel evil 49 Staff of destruction 50 Wand of clone monster 15 [2 in 4.87] Wand of drain life 50 Q12. How many attacks can I get with this weapon? Here is the table (for 5.x) for the number of blows for a given strength and dexterity. If your strength or dexterity is 18+xx, that is stored as 18/xx; thus, for example, you need an 18/90 strength to use the bottom row of the table with a katana (12 pounds). If you don't know the weight of a weapon, set the option "Show weights in inventory." /* used to calculate the number of blows the player gets in combat */ int8u blows_table[7][6] = { /* STR/W: 9 18 67 107 117 118 : DEX */ /* <2 */ { 1, 1, 1, 1, 1, 1 }, /* <3 */ { 1, 1, 1, 1, 2, 2 }, /* <4 */ { 1, 1, 1, 2, 2, 3 }, /* <5 */ { 1, 1, 2, 2, 3, 3 }, /* <7 */ { 1, 2, 2, 3, 3, 4 }, /* <9 */ { 1, 2, 2, 3, 4, 4 }, /* >9 */ { 2, 2, 3, 3, 4, 4 } }; Q13. How do you kill an ancient multi-hued dragon? Usually, you don't want to try; one gas breath from a full-strength AMHD does 693 damage, with no resistance. If you can get to speed 3 (one permanent speed item, and either another permanent speed item or a haste self spell or staff), you can try this technique. First, create (or find in a maze room) a wall with one open space on all four sides. . .#. . Stand on one side, with the dragon on the other side. When the dragon moves adjacent to you, attack it once, and then hide behind the pillar. The dragon can't see you, so it won't breathe, and will instead chase you to another side. Now attack once, and hide again, and so on until the dragon is finished. Q14. How do you kill an emperor lich? You can kill an emperor lich if you can get to speed 2, which is its speed. A mage or ranger can do this with the spell of haste self; anyone else needs a staff of speed, potion of haste self, or permanent speed item. You will also need about 10 cure critical wounds or cure serious wounds potions, and some item giving you free action. You also need some ranged spell attack. Liches take double damage from lightning in 5.x versions, so the spell of lightning bolt or wand of lightning balls is a good choice. Rogues and warriors will need several wands, with a total of about 30 charges to guarantee that they can kill the lich with them. A priest or paladin has Orb of Draining, which is even better. Now, try to line up with the lich while you are not adjacent to it, either in a room or a corridor. This gives you a chance to cast your spell. The lich will get one action. If it cast a spell and you resisted, or the spell didn't do anything harmful, you have another chance. If you were confused or blinded, drink a cure wounds potion; the lich isn't adjacent to you, so it can't hurt you. If the lich moved and is now adjacent to you, move back. Try to avoid getting cornered, and phase door or portal away if you are. A priest can make this easier by putting down a glyph of warding, but this must be done *before* the lich chases you across the glyph. (Don't stand on the glyph; it isn't foolproof.) If you run low on mana and don't have a wand, teleport out and come back later to finish the job. A priest with glyph of warding can also set up the following configuration (the exact length doesn't matter as long as you are within spell range): #L##### #^^...@ ####### The lich cannot cast spells from this position, because it cannot see you. As long as it doesn't break the glyphs, you are safe, and can fire Orb of Draining down the corridor; the lich will take some damage each time. If the lich breaks either glyph, run or teleport out, and continue the battle elsewhere. I do not advise trying this technique against an AMHD; it will probably break a glyph before the battle is over, and if your teleport spell fails, or if you haven't hasted yourself, the AMHD gets a chance to breathe. An emperor lich has 1520 hit points, plus anything additional that it gains by draining mana (6 points per mana point drained) and charges (40 points per charge). Never let it attack you in melee, because it can destroy your wands, healing itself in the process, as well as draining your experience and dexterity. If you can get to speed 3, faster than the lich, it is easy to kill; just fight, move back, fight, move back, and so on. You will still need a lot of cure wounds potions, unless you let it chase you around a pillar, as in the AMHD technique. Q15. What is the grape jelly trick? Does it work in Umoria 5.x? The Grape Jelly trick is a spoiler/workaround/trick which is no longer necessary in 5.1 and later versions. In 4.87, when your intelligence and constitution changed, your mana and hit points did not change. Thus, in order to get the benefit of the increased values, you have to let a grape jelly (or other creature, but grape jellies are otherwise harmless) drain you to a low level, and then drink restore life levels potions to go back up with the increased stats. Q16. I don't like haggling; can I change the source code to turn it off? If you have the source code for any 5.x version, you can turn off haggling with a simple change. Here is the change you would need to make. (Note: This is *not* an official patch.) In the source file store1.c, this is the routine for determining whether you need to haggle. You can change the function, or simply change the return(flagnoneed) to return(TRUE) to eliminate all haggling. The code here is from versions 5.5.1 and 5.5.2; the text of the function is slightly different in earlier versions. int noneedtobargain(store_num, minprice) int store_num; int32 minprice; { register int flagnoneed; int bargain_record; register store_type *s_ptr; s_ptr = &store[store_num]; if (s_ptr->good_buy == MAX_SHORT) return TRUE; bargain_record = (s_ptr->good_buy - 3 * s_ptr->bad_buy - 5); flagnoneed = ((bargain_record > 0) && ((long)bargain_record * (long)bargain_record > minprice/50)); return (flagnoneed); } Q17. How do you create objects in wizard mode? You will need the source; if you have only executables, get the source files constant.h and treasure.c from the archive, which contain the necessary definitions. This is an explanation of some of the parameters. Tval: This is defined in constant.h; it is the value for the item type. For example, TV_WAND is 65. Tchar: The character used to represent this object; it should usually be proper for the item type. Subval: This identifies the specific item. If you are duplicating an item from the item list, use the same subval (and tval) as that item; otherwise, don't. Use subvals 0-63 for items that shouldn't stack, 64-127 for items that should always stack (potions and scrolls), 193 or more for items that are generated in a group, and should stack as that group (arrows). Weight: In tenths of a pound. P1: Used for all special bonuses which don't appear elsewhere: bonus to stats/searching/stealth/speed, which stat to sustain (warning: constitution is 4 and dexterity 5), tunneling value, food value, light value of a lamp, torch, or flask of oil. For missiles, different values of P1 distinguish different groups of missiles; use small negative numbers if you create groups as a wizard. For bows, slings, and crossbows, the values identify the weapon type; use the same value that is used for the corresponding weapon in treasure.c. Flags: A hexadecimal number which contains: for wearable items, all special effects (bits beginning with TR_ in constant.h). for chests, trap flags (CH_ bits in constant.h) and treasure flags (CM_ bits in constant.h). The CM_WIN flag is cleared when you open a chest, so you can't create a chest with that bit set in order to get an instant win. for potions/scrolls/staffs/wands, the effects of using the item (see the items in treasure.c). Many potions have multiple effects (cure light wounds also cures blindness). for books, which spells are in the book (spell 1 is the units bit). Level: Level on which the item would be found. This affects the difficulty of using wands and staffs. The object will have no name, except for the inscription {wizard item}, and possibly a type name, such as "Potion of"; you can change the inscription. moria-5.6.debian.1/doc/ERRORS0000644000175000017500000000135205613574144013701 0ustar pjbpjbmoria.ms should: the backslashes in the direction table don't show up in the output for some reason explain non obvious spells/prayers, many of the priest spells are confusing, really should have a general section on spells explaining the 'G' command, how int/wis and level affects number of spells/prayers, how area effect spells work, centering before casting an area effect spell is very useful and perhaps other stuff about spells/magic explain the special inventory/equipment mode? explain how misc abilities depend on level, give table of class versus ability showing the relative gain per level values mention too-heavy weapons? says nothing about levels and EXP should mention that level 40 is the highest level that can be reached moria-5.6.debian.1/doc/moria.60000644000175000017500000000666505613574144014154 0ustar pjbpjb.TH MORIA 6 "" "Local" \" By default, this man page assumes moria was compiled with the original \" command set. If you are using the rogue like command set, then delete \" the first three characters on the following line. \" .ds O ROGUE_LIKE .if '\*(Bd'' .ds Bd moria .SH NAME moria \- a dungeon game .SH SYNOPSIS .B \*(Bd [ .B \-o ] [ .B \-r ] [ .B \-s ] [ .B \-S ] [ .B \-n ] [ .B \-w ] [ savefile ] .SH DESCRIPTION .I Moria\^ plays a dungeon game with you. It lets you generate a character, lets you buy equipment, and lets you wander in a fathomless dungeon while finding treasure and being attacked by monsters and fellow adventurers. Typing .B ? gives you a list of commands. .PP The ultimate object of .I moria is to kill the Balrog, which dwells on the 50th level of the dungeon, 2,500 feet underground. Most players never even reach the Balrog, and those that do seldom live to tell about it. .PP For a more complete description of the game, read the document .I The Dungeons of Moria. .PP By default, .I moria will save and restore games from a file called moria.save in your home directory. If the environment variable MORIA_SAV is defined, then .I moria will use that file name instead of the default. If MORIA_SAV is not a complete path name, then the savefile will be created or restored from the current directory. You can also explicitly specify a savefile on the command line. .PP If you use the \fB\-n\fP option, .I moria will create a new game, ignoring any savefile which may already exist. This works best when a savefile name is specified on the command line, as this will prevent .I moria from trying to overwrite the default savefile (if it exists) when you try to save your game. .PP You move in various directions .ie '\*O'ROGUE_LIKE' the same way you do in \fIrogue\fP(6). .el by pressing the numeric keypad keys, VMS-style. If you specify .if '\*O'ROGUE_LIKE' \fB\-o\fP, you move by pressing the numeric keypad .ie '\*O'ROGUE_LIKE' keys, VMS-style. .el \fB\-r\fP, you move the same way you do in \fIrogue\fP(6). You can also specify .ie '\*O'ROGUE_LIKE' \fB\-r\fP to force the \fIrogue\fP(6) like command set. .el \fB\-o\fP to force the VMS-style command set. These options will override defaults stored in the savefile. If these options are given multiple times, only the last one will take effect. .PP If you specify .BR \-s , .I moria prints all of the scores in the score file and exits. On a multiuser system, if you specify .BR \-S , .I moria prints prints only those scores belonging to you and then exits. .PP If you specify \fB\-w\fP, .I moria will start up in wizard mode. You can resurrect a dead character by using this option when starting the game. Resurrected characters are teleported to the town level and given zero hitpoints. Wizard mode is intended for debugging the game, and for experimenting with new features. Any other use is considered cheating. Games played with wizard mode are not scored. .SH AUTHORS The original version of Moria was written in VMS/Pascal by Robert Alan Koeneke, Jimmey Wayne Todd, Gary McAdoo, and others at the University of Oklahoma. This version was written by Jim Wilson at the University of California, Berkeley, and released with minor revisions by David Grabiner at Harvard University. .SH BUGS .PP A suspended game that gets a hangup signal will die without creating a save file. Rerolling with a % at the class prompt not implemented. For a more comprehensive list, see the ERRORS file in the source distribution. moria-5.6.debian.1/doc/moria2.txt0000644000175000017500000016213410757653306014705 0ustar pjbpjb The Dungeons of Moria Page 18 Rock, Granite Rock, Magma Intrusion, and Quartz Veins. Per- manent Rock is exactly that, permanent. Granite is very hard, therefore hard to dig through, and contains no valu- able metals. Magma and Quartz veins are softer and some- times bear valuable metals and gems, shown as a `$' or a `*' character. You can tell if the metal or gems are embedded into the wall by trying to move onto them. If you can't move over them, you'll have to dig them out. There is an option which causes magma and quartz to be displayed dif- ferently than other rock types. Tunneling can be VERY difficult by hand, so when you dig be sure to wield either a shovel or a pick. Magical shovels and picks can be found which allow the wielder to dig much faster than normal, and a good strength also helps. Tunneling can have a count. V - View scoreboard. This command will display the contents of the score board on the screen. On a multiuser system, typing `V' the first time will show only those scores from the score board that are yours, and typing `V' again will show all users' scores. a - Aim a wand. {z - zap} Wands must be aimed in a direction to be used. Wands are magical devices and therefore use the Magical Devices abil- ity of the player. They will either affect the first object/creature encountered, or affect anything in a given direction, depending upon the wand. An obstruction such as a door or wall will generally stop the effects of a wand from traveling further. b - Browse a book. {P - peruse} You can only read a book if you are of its realm. Therefore a magic user could read a magic book, but not a holy book. Warriors will not be able to read either kind of book. When the browse command is used, all of the spells or prayers contained therein are displayed, along with information such as their level, the amount of mana used up in casting them, and whether or not you know the spell or prayer. There are a total of 31 different magical spells in four books, and 31 different prayers in four books. c - Close a door. Nonintelligent and certain other creatures will not be able to open a door. Therefore shutting doors can be a life saver. You must be adjacent to an open door, and you cannot close broken doors. Bashing a door open will break it. d - Drop an object from your inventory. You can drop an object onto the floor beneath you if that floor spot does not already contain an object. Doors and traps are considered objects in this sense. If you have several objects of the same kind, you will be prompted for The Dungeons of Moria Page 19 dropping one or all of them. It is possible to directly drop things which you are wielding or wearing. e - Display a list of equipment being used. Use the Equipment command to display a list of objects currently being used by your character. Each object has a specific place where it is placed, and that only one object of each type may be used at any one time, excepting rings of which two can be worn, one on each hand. f - Fire/Throw an object/use a missile weapon. {t - throw} You may throw any object carried by your character. Depend- ing upon the weight of an object, it may travel across a room or drop down beside you. If you throw an object such as an arrow, only one will be used at a time. If you throw at a creature, your chance of hitting the creature is determined by your plusses to hit, your ability at throwing, and the object's plusses to hit. Once the creature is hit, the object may or may not do any actual damage to it. Certain objects in the dungeon can do great amounts of damage when thrown, but it's for you to figure out the obscure ones. Oil flasks are considered to be lit before thrown; therefore, they will do fire damage to a creature if they hit it. To use a bow with arrows, simply wield the bow and throw the arrows. Extra plusses to damage and hitting are gained by wielding the proper weapon and throwing the corresponding ammo. A heavy crossbow with bolts for example, is a killer... i - Display a list of objects being carried. This command displays a list of all objects being carried, but not currently in use. You may carry up to 22 different kinds of objects, not including those in your equipment list. Depending upon your strength, you will be able carry many identical objects before hitting your weight limit. j - Jam a door with an iron spike. {S - spike} Most humanoid and many intelligent creatures can simply open a closed door, and can eventually get through a locked door. Therefore you may spike a door in order to jam it. Each spike used on a door will increase its strength, although the more spikes you add, the less effect each additional spike has. It is very easy to jam a door so much as to make it impossible for your character to bash it down, so spike doors wisely. The bigger a creature is, the easier it can bash a door down. Therefore twenty or more spikes might be necessary to slow down a dragon, where one spike would slow down a kobold. This command can be counted. l - Look in a direction. {x - examine} The Look command is useful in identifying the exact type of The Dungeons of Moria Page 20 object or creature shown on the screen. Also, if a creature is on top of an object, the look command will describe both. You can see creatures and objects up to 200 feet away (20 spaces). You may freely use the Look command without the creatures getting a move on you. Looking in a particular direction sees everything within a cone of vision which just overlaps the cones of the two adjacent directions. Looking with the null direction `5' (or `.') sees everything which there is to be seen. You are also able to access you monster memories with this command. If you see a creature, you are prompted to ask if you wish to see a short paragraph of information about your experiences with that creature. See also the section on being attacked. m - Cast a magic spell. To cast a spell, a character must have previously learned it, and must also have in the inventory a magical book from which the spell may be read. Each spell has a chance of failure which starts out fairly large but decreases as a character gains levels. If a character does not have enough mana, the chance of failure is greatly increased, and he gambles on losing a point of constitution. You will be prompted for confirmation before trying to cast a spell when you don't have enough mana. Since a character must read the spell from a book, he cannot be blind or confused when cast- ing a spell, and there must be some light present. o - Open a door, chest, or lock. To open an object such as a door or chest, you must use the Open command. If the object is locked, the Open command will attempt to pick the lock, based on your ability at disarming. If an object is trapped and you open it, the trap will be set off. This command can be counted, because you may need several tries to get a locked door or chest open. p - Read a prayer. To pay effectively, a character must have learned the prayer, and must also have in the inventory a holy book from which the prayer may be read. Each prayer has a chance of being ignored which starts out fairly large but decreases as a character gains levels. If a character does not have enough mana, the chance of failure is greatly increased, and he gambles on losing a point of constitution. You will be prompted for confirmation before trying to pray when you don't have enough mana. Since a character must read the prayer from a book, he cannot be blind or confused when praying, and there must be some light present. q - Quaff a potion. To drink a potion use the Quaff command. A potion affects The Dungeons of Moria Page 21 the player in some manner. The effects of the potion may be immediately noticed, or they may be subtle and unnoticed. r - Read a scroll. To read a scroll use the Read command. Most scroll spells either affect the player or the area around the player; a few cases such as identify scrolls act on other objects. Two scrolls, the identify scroll and the recharge scroll, have titles which can be read without setting them off, and by pressing ESCAPE can be saved for future use. s - Search general area one turn. The Search command can be used to locate hidden traps and secret doors about the player. More than a single turn of searching will be required in most cases. You should always search a chest before trying to open it because they are generally trapped. This command can be counted, which is useful if you are really sure of finding something eventu- ally. A counted search ends as soon as anything is found. t - Take off a piece of equipment. {T} Use the Take Off command to remove an object from use, and return it to your inventory. Occasionally you will run into a cursed item which cannot be removed. Cursed items are always bad, and can only be taken off after removing the curse. u - Use a staff. {Z - Zap} The Use command will activate a staff. Like scrolls, most staffs have an area effect. Because staffs are generally more powerful than most other items, they are also harder to use correctly. v - Display current version of game. The Version command displays the credits for the current version of moria. w - Wear or wield an item being carried. To wear or wield an object in your inventory, use the Wear/Wield command. If another object is already in use for the same function, it is automatically removed first; if you are wearing two rings, you are given a choice of which one to remove. An object's bonuses cannot be gained until it is worn or wielded. x - Exchange primary and secondary weapons. {X} A secondary weapon is any weapon which may be needed often. Instead of searching through your inventory, you may use the exchange command to keep the weapon ready. For instance, if you wanted to use your bow most of the time, but needed a sword for close combat, you could wield your sword, use the exchange command to make it the secondary weapon, then wield your bow. If the sword was suddenly needed, simply use the exchange command to switch between the bow and the sword. The Dungeons of Moria Page 22 / - Identify a character shown on screen. Use the identify command to find out what a character displayed on the screen stands for. For instance, by press- ing `/.', you can find out that the `.' stands for a floor spot. When used with a creature, the identify command will tell you only what class of creature the symbol stands for, not the specific creature; therefore, use the look command for this information. If you identify the character for a creature in your monster memory, you are also prompted to ask if you wish to see a paragraph of information on those creatures identified by the given character. Several creatures may be identified in this way. Typing ESCAPE after the paragraph for any creature will abort back to command level. See also the section on being attacked. ? - Display a list of commands. The ? command displays a quick reference help page on the screen. - - Move without pickup. This is followed by a move command, and causes you to move over any object without picking it up. You can associate a count with this command. = - Set options. This is a free move, to set various moria options. The available options are: (1) Cut known corners when running. This is on by default, and the only reason for switching it off would be if you had the search flag on and wished to look for doors in the extremity of every corner. (2) Examine potential corners when running. This is on by default, and allows you to run along an unknown curving cor- ridor. If, however, you are running from a creature, you may wish to switch this option off, because the creature will cut the corner. (3) Print self during a run. This is off by default, which gives faster screen updating. (4) Stop when map sector changes. This is off by default, but can be switched on if you wish to stop running whenever a new part of the dungeon appears in view. (5) Treat open doors as empty space while running. This is off by default, in which case you stop whenever you run up to an open door. (6) Prompt to pick up objects. This is off by default, in which case stepping over an object automatically causes you to The Dungeons of Moria Page 23 pick it up. With the option on, you get prompted in all such cases with a description of the object to see if you really want to take it. (7) Rogue like command set. This option controls the command set in use. It is off by default. (8) Show weights in inventory. This is off by default: switch- ing it on causes the inventory and equipment listings to include the weight of all objects. This may be useful to know if your pack is getting too heavy. (9) Highlight and notice mineral seams. This is off by default. Switching it on causes quartz and magma to be displayed as `%' instead of `#'; also, it causes the look command to treat them as interesting objects. This is handy when min- ing. Setting this option does not immediately highlight all minerals, but only those which are subsequently displayed. To display all minerals, just move the map around a bit with the `Where' (or `Locate') command. (10)Beep for invalid character. This is on by default. When on, the program will beep for most invalid characters, such as trying to choose a spell that you haven't learned yet. When off, there are no such beeps. (11)Display rest/repeat counts. This is on by default. When on, the program will progressively display the remaining turns left while resting, and for repeated commands. For those trying to play over a 2400 bps or less connection, or for those playing on very slow microcomputers, turning this off will make resting and repeated commands work much fas- ter. The setting of all these options persist in your savefile, even after you die. ^P - Previous message. The Control-P command will redisplay the last message printed on the message line at the top of your screen. A second such command will display all of the saved messages. You may also give this command a count to specify the number of previous messages to display. At present, only 22 mes- sages are saved. ^K - Quit the game without saving. {Q} To exit the game without saving your character (i.e. kill him/her) use the Control-K command. Once exited in this manner, your character is nonrecoverable. ^X - Save your character and exit the game. To save your game so that it can be restarted later, use the Control-X command. Save files will also be generated if the game crashes due to a system error. When you die, a reduced The Dungeons of Moria Page 24 save file is produced containing only your monster memory, and your option settings. { - Inscribe an object. This command can be used to inscribe any short string on an object. Inscriptions are limited to twelve characters. The inscription applies only to the particular object, it is not automatically transferred to all similar objects. Under certain circumstances, moria will itself inscribe objects: if they have been discovered to be cursed or enchanted, or if they have been sampled without being identified. In this last case, moria does in fact carefully inscribe every such item. If the inscription on an item is a single digit, that digit can be used to refer to it when using, wearing, or wielding an item from your pack. For example, if you keep a pick in your pack with the inscription 1, you can switch to the pick by wielding item 1 without checking your full inventory list to find out which item the pick is. ! - Shell out of game. Use the Shell command `!' to temporarily exit the game to execute UNIX or MSDOS commands. You may reenter the game by typing exit to end the spawned process. This is not imple- mented in the Macintosh version. < - Go up an up staircase. If you move onto an up staircase you may use the `<' command to go up one level. There is always one staircase going up on every level except for the town level (this does not mean it's easy to find). Going up a staircase will always take you to a new dungeon area except for the town level, which remains the same for the duration of your character. > - Go down a down staircase. If you are on top of a down staircase you may use the `>' command to go down one level. There are always two or three staircases going down on each level, except the town level which has only one. Going down will always take you to a new dungeon area. . - Move in direction. {shift} The Run command will move you in the indicated direction until either you have to make a choice as between two direc- tions, or something interesting happens. There are options which determine behavior at corners, and at screen boun- daries. More precisely, the conditions which stop a run are as follows: (1) A creature appears on the screen, one already on the screen moves, or a creature attacks you or casts a spell at you. (2) You move next to an object, or a feature such as a door or The Dungeons of Moria Page 25 trap. (3) You come to the end of open space, or the end of a passage, or a junction of passages, or a hole in a wall. (4) Anything typed during a run causes the run to stop. The character causing this to occur is ignored. It is best to use a space, which is ignored as a command, just in case the run stops just before you type the character. (5) Various changes of state, such as recovery from fear or loss of heroism, will stop a run. Corners are more complex. A corner allows a choice between adjacent rectangular and diagonal directions. If you can see walls which ensure that the diagonal gives a faster traversal, then action is determined by the "cut corners" options. If it is set, then you move diagonally through the corner. This gives you maximum speed (as is nice if you are fleeing a hidden creature). On the other hand, this option should not be set if you want more careful coverage (as when you are searching) so that you take two moves through the corner. At a potential corner, where walls are not yet visible ahead of the rectangular direction, the "examine corners" option is considered. If set, you will move straight into the corner, which will light up all the corner and so determine where you can go from there. This allows you to follow corners in new passages. If the option is not set, you stop. This allows highly cautious running where you want to stop at all potential choice points. If you move off the screen while running, then a new section of the dungeon is displayed and the run continues. However, if the "stop when map changes" option is set, you will stop. Again, this is an option for nervous players; after all, there may be a dragon on the new screen. 6. The Town Level The town level is where you will begin your adventure. The town consists of six buildings, each with an entrance, some townspeo- ple, and a wall which surrounds the town. The first time you are in town it will be daytime, but you may return to find that dark- ness has fallen. (Note that some spells may act differently in the town level.) 6.1. Townspeople The town contains many different kinds of people. There are the street urchins, young children who will mob an adventurer for money, and seem to come out of the woodwork when excited. The Dungeons of Moria Page 26 Blubbering Idiots are a constant annoyance, but not harmful. Public drunks wander about the town singing, and are of no threat to anyone. Sneaky rogues hang about watching for a likely victim to mug. And finally, what town would be complete without a swarm of half-drunk warriors, who take offense or become annoyed just for the fun of it. Most of the townspeople should be avoided by the largest possible distance when you wander from store to store. Fights will break out though, so be prepared. Since your character grew up in this world of intrigue, no experience is awarded for killing on the town level. 6.2. Supplies Your character will begin his adventure with some supplies already on him. Use the Inventory `i' command to check what these supplies are. It will be necessary to buy other supplies before continuing into the dungeon, however, so be sure to enter each of the stores. 6.3. Town Buildings You may enter any of the stores, if they are open, and barter with the owner for items you can afford. When bartering, you enter prices you will pay (or accept) for some object. You can either enter the absolute amount, or precede a number with a plus or minus sign to give a positive or negative increment on your previous offer. If you have previously given an increment or decrement amount, you can just type RETURN, and the program will use the last increment amount that you typed. But be warned that the owners can easily be insulted, and may even throw you out for a while if you insult them too often. To enter a store, simply move onto the entrance represented by the numbers 1 through 6. If you consistently bargain well in a store, that is, you reach the final offer much more often than not, then the store owner will eventually recognize that you are a superb haggler, and will go directly to the final offer instead of haggling with you. Items which cost less than 10 gold pieces do not count, as hag- gling well with these items is usually either very easy or almost impossible. Once inside a store, the store inventory will appear on the screen along with a set of options for your character. You may browse the store's inventory if it takes more than one page to display, and you may sell to, or purchase items from, his inven- tory. You can execute your inventory and equipment commands to see what you are carrying. Not shown with the options are the wear, take off, and exchange commands which will also work, but were excluded to keep the options simple. The Dungeons of Moria Page 27 Stores do not always have everything in stock. As the game progresses, they may get new items, so check from time to time. Also, if you sell them an item, it may get sold to a customer while you are adventuring, so don't always expect to be able to get back everything you have sold. Store owners will not buy harmful or useless items. If an object is unidentified, they will pay you some base price for it. Once they have bought it they will immediately identify the object. If it is a good object, they will add it to their inventory. If it was a bad bargain, they simply throw the item away. In any case, you may receive some knowledge of the item if another is encountered. The General Store The General Store sells foods, drinks, some clothing, torches, lamps, oil, shovels, picks, and spikes. All of these items, and some others, can be sold back to the Gen- eral store for money. The entrance to the General Store is a `1'. The Armory The Armory is where the town's armor is fashioned. All sorts of protective gear may be bought and sold here. The entrance to the Armory is a `2'. The Weaponsmith's Shop The Weaponsmith's Shop is where the town's weapons are fashioned. Hand and missile weapons may be purchased and sold here, along with arrows, bolts, and shots. The entrance to the Weaponsmith's is a `3'. The Temple The Temple deals in healing and restoration potions, as well as bless scrolls, word of recall scrolls, some approved pri- estly weapons, etc. The entrance to the Temple is a `4'. The Alchemy Shop The Alchemy Shop deals in all manner of potions and scrolls. The entrance to the Alchemy Shop is a `5'. The Magic User's Shop The Magic User's Shop is the most expensive of all the stores. It deals in all sorts of rings, wands, amulets, and staves. The entrance to the Magic Shop is a `6'. 7. Within The Dungeon Once your character is adequately supplied with food, light, armor, and weapons, he is ready to enter the dungeon. Move on top of the `>' symbol and use the down `>' command. Your charac- ter enters a maze of interconnecting staircases and finally passes through a one-way door. He is now on the first level of The Dungeons of Moria Page 28 the dungeon (50 feet), and must survive many horrible and chal- lenging encounters to find the treasure lying about. There are two sources for light once inside the dungeon: per- manent light which has been magically placed within rooms, and a light source carried by the player. If neither is present, the character will be unable to map or see any attackers. Lack of light will also affect searching, picking locks, and disarming. A character must wield a torch or lamp in order to supply his own light. Once a torch or lamp has only 50 or less turns left before burning out, the message "Your light is growing faint" will be displayed at random intervals. Once a torch is burnt out, it is useless and can be dropped. A lamp or lantern can be refilled with oil by using the Fill `F' command. You must of course be carrying extra oil to refill a lantern. 8. Attacking and Being Attacked Attacking is simple in moria. If you move into a creature, you attack it. You can attack from a distance by firing a missile, or by magical means such as aiming a wand. Creatures attack in the same way; if they move into you, they attack you. Some creatures can also cast spells from a distance, and others can breathe fire or worse on you from a distance. Creatures moving in walls can not be attacked by wands and other magic attacks normally stopped by walls. You can attack a creature in a wall normally though by trying to move into the wall space containing the creature. However, in order to attack an invisible creature in a wall, you must tunnel into the wall containing the creature. If you just try to move into the wall, you will bump your head and look quite silly. If you are wielding a weapon, the damage for the weapon is used when you hit a creature. Otherwise, you get two fist strikes. Very strong creatures can do a lot of damage with their fists... You may have a primary weapon, and a secondary weapon which is kept on your belt or shoulder for immediate use. You can switch between your primary and secondary weapons with the exchange com- mand. Be sure to wield the proper weapon when fighting. Hitting a dragon over the head with a bow will simply make him mad, and get you killed. Missile weapons, such as bows, can be wielded, and then the proper missile, in this case an arrow, can be fired across the room into a target. Missiles can be used without the proper mis- sile weapon, but used together they have a greater range and do far more damage. Hits and misses are determined by ability to hit versus armor class. A hit is a strike that does some damage; a miss may in fact reach a target, but fails to do any damage. Higher armor The Dungeons of Moria Page 29 classes make it harder to do damage, and so lead to more misses. 8.1. Monster Memories There are hundreds of different creatures in the mines of moria, many of which look the same on the screen. The exact species of a creature can be discovered by looking at it. It is also very difficult to keep track of the capabilities of various creatures. Rather than forcing you to keep notes, moria automatically keeps track of your experiences with a particular creature. This is called the monster memory. You monster memory recalls the par- ticular attacks of each creature which you have suffered, as well as recalling if you have observed them to multiply or move errat- ically, or drop treasure, or many other attributes. If you have killed enough of a particular creature, or suffered enough attacks, recalling the monster memory may also provide you with information not otherwise available, such as a armor class or hit dice. These are not explained, but may be useful to give the relative danger of each creature. This memory can be passed on to a new character even after you die, by means of a reduced save file. 8.2. Your Weapon Carrying a weapon in your backpack does you no good. You must wield a weapon before it can be used in a fight. A secondary weapon can be kept by wielding it and then using the exchange command. A secondary weapon is not in use, simply ready to be switched with the current weapon if needed. Weapons have two main characteristics, their ability to hit and their ability to do damage, expressed as `(+#,+#)'. A normal weapon would be `(+0,+0)'. Many weapons in moria have magical bonuses to hit and/or do damage. Some weapons are cursed, and have penalties that hurt the player. Cursed weapons cannot be unwielded until the curse is lifted. Moria assumes that your youth in the rough environment near the dungeons has taught you the relative merits of different weapons, and displays as part of their description the damage dice which define their capabilities. The ability to damage is added to the dice roll for that weapon. The dice used for a given weapon is displayed as `#d#'. The first number indicates how many dice to roll, and the second indicates how many sides they have. A "2d6" weapon will give damage from 2 to 12, plus any damage bonus. The weight of a weapon is also a consideration. Heavy weapons may hit harder, but they are also harder to use. Depending on your strength and the weight of the weapon, you may get several hits in one turn. Missile booster weapons, such as bows, have their characteristics The Dungeons of Moria Page 30 added to those of the missile used, if the proper weapon/missile combination is used. Also, these weapons will multiply the base damage of the missile by a number from 2 to 4, depending on the strength of the weapon. This multiplier is displayed as `(x#)'. Although you receive any magical bonuses an unidentified weapon may possess when you wield it, those bonuses will not be added in to the displayed values of to-hit and to-dam on your character sheet. You must identify the weapon before the displayed values reflect the real values used. Finally, some rare weapons have special abilities. These are called ego weapons, and are feared by great and meek. An ego sword must be wielded to receive benefit of its abilities. Special weapons are denoted by the following abbreviations: DF - Defender. A magical weapon that helps the wielder defend himself, thus increasing his/her armor class, and protecting him/her against damage from fire, frost, acid, lightning, and falls. This weapon also will increase your stealth, let you see invisible creatures, protect you from paralyzation attacks, and help you regenerate hit points and mana faster. As a result of the regeneration ability, you will use up food faster than normal while wielding such a weapon. FB - Frost Brand. A magical weapon of ice that delivers a cold critical to heat based creatures. It will inflict one and a half times the normal damage when used against a heat based creature. FT - Flame Tongue. A magical weapon of flame that delivers a heat critical to cold based creatures. It will inflict one and a half times the normal damage when used against cold based or inflamm- able creatures. HA - Holy Avenger. A Holy Avenger is one of the most powerful of weapons. A Holy Avenger will increase your strength and your armor class. This weapon will do extra damage when used against evil and undead creatures, and will also give you the abil- ity to see invisible creatures. SA - Slay Animal. A Slay Animal weapon is a special purpose weapon whose sole intent is to destroy all the dangerous animals in the world. An animal is any creature natural to the world. Therefore an orc would not be an animal, but a giant snake would be. This will inflict twice the normal amount of damage when used against an animal. SD - Slay Dragon. The Dungeons of Moria Page 31 A Slay Dragon weapon is a special purpose weapon whose sole intent is to destroy dragon-kind. Therefore, when used against a dragon, the amount of damage done is four times the normal amount. SE - Slay Evil. A Slay Evil weapon is a special purpose weapon whose sole intent is to destroy all forms of evil. When used against an evil creature, either alive or undead, the damage done twice the normal amount. SU - Slay Undead. A Slay Undead weapon is a special purpose weapon whose sole intent is to destroy all forms of undead. This weapon is hated and feared by the intelligent undead, for a single blow from this weapon will inflict three times the normal amount of damage. This weapon also gives you the ability to see invisible creatures, which is especially useful against undead, since many of them are normally invisible. 8.3. Body and Shield Bashes Weight is the primary factor in being able to bash something, but strength plays a role too. After bashing, a character may be off balance for several rounds depending upon his dexterity. Doors can be broken down by bashing them. Once a door is bashed open, it is forever useless and cannot be closed. Chests too may be bashed open, but be warned that the careless smashing of a chest often ruins the contents. Bashing open a chest will not disarm any traps it may contain, but does allow the strong and ignorant to see what is inside. Finally, a creature may be bashed. If a shield is currently being worn, the bash is a shield bash and will do more damage. In either case, a bash may throw an opponent off balance for a number of rounds, allowing a player to get in a free hit or more. If the player is thrown off balance, his opponent may get free hits on him. This is a risky attack. 8.4. Your Armor Class Armor class is a number that describes the amount and the quality of armor being worn. Armor class will generally run from about 0 to 60, but could become negative or greater than 60 in rare cases. The larger your armor class, the more protective it is. A nega- tive armor class would actually help get you hit. Armor protects you in three manners. One, it makes you harder to be hit for damage. A hit for no damage is the same as a miss. Two, good The Dungeons of Moria Page 32 armor will absorb some of the damage that your character would have taken. An armor class of 30 would absorb 15% of any damage meant for him. Three, acid damage is reduced by wearing body armor. It is obvious that a high armor class is a must for sur- viving the lower levels of moria. Each piece of armor has an armor class adjustment, and a magical bonus. Armor bought in town will have these values displayed with its description. Armor that is found within the dungeon must be identified before these values will be displayed. All armor always has the base armor class displayed, to which the bonus is added. It is always possible to figure this out anyway, by watching the effect it has on your displayed armor class. Armor class values are always displayed between a set of brackets as `[#]' or `[#,+#]'. The first value is the armor class of the item. The second number is the magical bonus of the item which is only displayed if known, and will always have a sign preceding the value. There are a few cases where the form `[+#]' is used, meaning the object has no armor class, only a magical armor bonus if worn. Body armor may also have a (-#) displayed in parentheses; this is a penalty to hit, because the bulk of the armor makes it more difficult to swing a weapon freely. Some pieces of armor will possess special abilities denoted by the following abbreviations: RA - Resist Acid. A character using such an object will take only one-third normal damage from any acid thrown upon him. In addition, armor so enchanted will resist the acid's effects and not be damaged by it. RC - Resist Cold. A character using a resist cold object will take only one- third damage from frost and cold. RF - Resist Fire. A character using a resist fire object will take only one- third damage from heat and fire. RL - Resist Lightning. A character using a resist lightning object will take only one-third damage from electrical attacks. R - Resistance. A character wearing armor with this ability will have resis- tance to Acid, Cold, Fire, and Lightning as explained in each part above. 8.5. Crowns Some crowns also have special magical abilities that improve your The Dungeons of Moria Page 33 chances in a battle. Crown of Might This is the great crown of the warriors. The wearer will have an increased strength, dexterity, and constitution, and will also be immune to any foe's attempt to slow or paralyze him or her. Crown of the Magi This is the great crown of the wizards. The wearer will have an increased intelligence, and will also be given resistance against fire, frost, acid, and lightning. Crown of Lordliness This is the great crown of the priests. The wearer will have an increased wisdom and charisma. Crown of Seeing This is the great crown of the rogues. The wearer will be able to see even invisible creatures, and will have an increased ability to locate traps and secret doors. Crown of Regeneration This crown will help you regenerate hit points and mana more quickly than normal, allowing you to fight longer before needing to rest. You will use of food faster than normal while wearing this crown because of the regenerative effects. Crown of Beauty This crown looks impressive, and will increase your charisma, but is otherwise not useful. 9. Objects Found In The Dungeon The mines are full of objects just waiting to be picked up and used. How did they get there? Well, the main source for useful items are all the foolish adventurers that proceeded into the dungeon before you. They get killed, and the helpful creatures scatter the various treasure throughout the dungeon. Most cursed items are placed there by the joyful evil sorcerers, who enjoy a good joke when it gets you killed. You pick up objects by moving on top of them. You can carry up to 22 different items in your backpack while wearing and wielding many others. Although you are limited to 22 different items, you may be carrying several items of each kind, restricted only by the amount of weight your character can carry. Your weight limit is determined by your strength. Only one object may occupy a given floor location, which may or may not also contain one creature. Doors, traps, and staircases are considered objects for this purpose. The Dungeons of Moria Page 34 If you try to carry more weight than your limit, you will move more slowly than normal until you drop the extra weight. If picking up an object would take you over your weight limit, then you will be asked whether you really want to pick it up. It is a good idea to leave the object alone if you are fleeing from a monster. Many objects found within the dungeon have special commands for their use. Wands must be Aimed, staffs must be Used, scrolls must be Read, and potions must be Quaffed. In any case, you must first be able to carry an object before you can use it. Some objects, such as chests, are very complex. Chests contain other objects and may be trapped, and/or locked. Read the list of player commands carefully for a further understanding of chests. One item in particular will be discussed here. The scroll of "Word-of-Recall" can be found within the dungeon, or bought at the temple in town. It acts in two manners, depending upon your current location. If read within the dungeon, it will teleport you back to town. If read in town, it will teleport you back down to the deepest level of the dungeon on which your character has previously been. This makes the scroll very useful for get- ting back to the deeper levels of moria. Once the scroll has been read, it takes a while for the spell to act, so don't expect it to save you in a crisis. The game provides some automatic inscriptions to help you keep track of your possessions. Wands and staves which are known to be empty will be inscribed with "empty". Objects which have been tried at least once, but haven't been identified yet will be inscribed with "tried". Cursed objects are inscribed with "damned". Also, occasionally you will notice that something in your inventory or equipment list seems to be magical. High level characters are much more likely to notice this than beginning characters. When you do notice this, the item in question will be inscribed with "magik". And lastly, a final warning: not all objects are what they seem. Skeletons lying peacefully about the dungeon have been known to get up... 9.1. Cursed Objects Some objects, mainly armor and weapons, have had curses laid upon them. These horrible objects will look like any other normal item, but will detract from your character's stats or abilities if worn. They will also be impossible to remove until a remove curse is done. If you wear or wield a cursed item, you will immediately feel something wrong. The item will also be inscribed "damned". The Dungeons of Moria Page 35 9.2. Mining Much of the treasure within the dungeon can be found only by min- ing it out of the walls. Many rich strikes exist within each level, but must be found and mined. Quartz veins are the richest, yielding the most metals and gems, but magma veins will have some hordes hidden within. Mining is virtually impossible without a pick or shovel. Picks and shovels have an additional magical ability expressed as `(+#)'. The higher the number, the better the magical digging ability of the tool. A pick or shovel also has plusses to hit and damage, and can be used as a weapon. When a vein of quartz or magma is located, the character should wield his pick or shovel and begin digging out a section. When that section is removed, he should locate another section of the vein, and begin the process again. Since granite rock is much harder to dig through, it is much faster to follow the vein exactly and dig around the granite. There is an option for highlighting magma and quartz. If the character has a scroll or staff of treasure location, he can immediately locate all strikes of treasure within a vein shown on the screen. This makes mining much easier and more pro- fitable. It is sometimes possible to get a character trapped within the dungeon by using various magical spells and items. So it is a very good idea to always carry some kind of digging tool, even when you are not planning on tunneling for treasure. 9.3. Staircases, Secret Doors, Passages, and Rooms Staircases are the manner in which you get deeper, or climb out of the dungeon. The symbols for the up and down staircases are the same as the commands to use them. A `<' represents an up staircase and a `>' represents a down staircase. You must move your character over the staircase before you can use them. Each level has at least one up staircase, and at least two down staircases. There are no exceptions to this rule. You may have trouble finding some well hidden secret doors, but the stairs are there. Many secret doors are used within the dungeon to confuse and demoralize adventurers foolish enough to enter. But with some luck, and lots of concentration, you can find these secret doors. Secret doors will sometimes hide rooms or corridors, or even entire sections of that level of the dungeon. Sometimes they simply hide small empty closets or even dead ends. Creatures in the dungeon will generally know and use these secret The Dungeons of Moria Page 36 doors. If they leave one open, you will be able to go right through it. If they close it behind them you will have to search for the catch first. Once a secret door has been discovered by you, it is drawn as a known door and no more searching will be required to use it. 10. Winning The Game Once your character has progressed into killing dragons with but a mean glance and snap of his fingers, he may be ready to take on the Balrog. The Balrog will appear on most levels after level 49, so don't go down there until you are ready for him. The Balrog cannot be killed in some of the easier methods used on normal creatures. Because of the Balrog's cunning, he will teleport away to another level if a spell such as destruction is used upon him, and the Balrog cannot be polymorphed, slept, con- fused, or genocided. Magical spells like coldball are effective against him, as are weapons, but he is difficult to kill, and if allowed to escape to another level can heal himself. If you should actually survive the attempt of killing the Balrog, you will receive the status of WINNER. Since you have defeated the toughest creature alive, your character is ready to retire and cannot be saved. When you quit the game, your character receives a surprise bonus score. 11. Upon Death and Dying If your character falls below 0 hit points, he has died and can- not be restored. A tombstone showing information about your character will be displayed. You are also permitted to get a record of your character, and all your equipment (identified) either on the screen or in a file. Your character will leave behind a reduced save file, which con- tains only the monster memory and your option choices. It may be restored, in which case the new character is generated exactly as if the file was not there, but the new player will find his mon- ster memory containing all the experience of past incarnations. 12. Wizards There are rumors of moria Wizards which, if asked nicely, can explain details of the moria game that seem complicated to beginners. moria-5.6.debian.1/doc/dragon.inf0000644000175000017500000000472505613574145014722 0ustar pjbpjb Every breath weapon does 1/3 of the monster's current hit points, except lightning, which does 1/4. Acid damage is then halved if you have any armor to corrode, or divided by 4 if you have resist acid and some armor. Cold or fire damage is divided by 3 if you have permanent resistance (from a ring, armor, or weapon) or temporary resistance (from a potion or priest spell), and by 9 if you have both. Lightning damage is divided by 3 if you have resistance. Gas damage always has full effect. Ancient Multi-Hued Dragon: (40/276) 2080 total hit points lightning: 520/173 acid: 693/347/173 fire/cold: 693/231/77 gas: 693 Even a 40th level half-troll warrior with 18/100 constitution, heroism, and superheroism would probably not have 693 hit points. Thus you must never fight AMHD's if you are giving them any opportunity to breathe on you. I don't like to go down to level 40 unless I have 231 hit points and resistance, so that I can survive 4 out of 5 breaths from off-screen AMHD's. Ancient Green Dragon: (39/269) 720 total hit points gas: 240 Ancient White Dragon: (38/263) 704 total hit points cold: 235/78/26 Ancient Blue Dragon: (39/268) 696 total hit points lightning: 174/58 Ancient Black Dragon: (39/270) 720 total hit points acid: 240/120/60 Ancient Red Dragon: (40/273) 840 total hit points fire: 280/93/31 Balrog: 3000 total hit points fire: 1000/333/111 Thus a mage with less than 333 hp can be killed by one breath from the Balrog, before he gets a chance to drink invulnerability potions. For a mage to get 333 hp, he must be human, and he must use the grape jelly trick. Mature Multi-Hued Dragon: (38/262) 640 total hit points lightning: 160/53 acid: 213/107/53 fire/cold: 213/71/24 gas: 213 Mature Green Dragon: (36/256) 384 total hit points gas: 128 Mature White Dragon: (35/250) 384 total hit points cold: 128/43/14 Mature Blue Dragon: (36/255) 384 total hit points lightning: 96/32 Mature Black Dragon: (37/261) 464 total hit points acid: 155/77/39 Mature Red Dragon: (37/260) 480 total hit points fire: 160/53/18 Young Multi-Hued Dragon: (36/254) 320 total hit points lightning: 80/27 acid: 107/53/27 fire/cold: 107/36/12 gas: 107 moria-5.6.debian.1/doc/README0000644000175000017500000000274705613574144013633 0ustar pjbpjbFEATURES.NEW mentions all of the important user visible changes from umoria 4.87 to umoria 5.x. dragon.inf Gives spoiler info on dragons. exp.doc Documents how experience works. Should be part of the manual. history is a brief history of the program umoria. moria.6 is the nroff source for a man page for umoria. Use the command 'nroff -man moria.6' to view it. By default, it assumes that umoria was compiled with the original command set. If you compiled umoria with the rogue like command set, then remove the three characters defore the .ds command at the start for a more appropriate man page. moria.man is an already processed copy of the man page (with bold and underlined characters removed) for those without the nroff program. moria1.ms, moria2.ms is the document "The Dungeons of Moria". It is a complete description of the game. You may want to adjust the margin and line length values at the beginning. To view it, use the command 'tbl moria1.ms moria1.ms | nroff -ms'. It is split into two parts so that it can be easily mailed. moria1.txt, moria2.txt is an already processed copy of the document "The Dungeons of Moria" (with bold and underlined characters removed) for those without the nroff program. It is split into two parts so that it can be easily mailed. pronounc explains how to pronounce the name moria. spells.doc Documents how spells work. Should be part of the manual. where.inf gives info on how to obtain the various versions of moria. moria-5.6.debian.1/doc/moria1.ms0000644000175000017500000015421711074752413014477 0ustar pjbpjb.\"This is a very modified version of the documentation .\"for the original VMS game. Changes were made to reflect differences .\"found in the UNIX port by James E. Wilson. .\" .\" "tbl moria1.ms moria2.ms | nroff -ms" .\" .\" You might wanna change these two values: .RP .nr PO 1i .nr LL 6.5i .ds LH "The Dungeons of Moria .ds CH " .ds RH "Page % .ds LF " .ds CF " .ds RF " .TL The Dungeons of Moria .AU Robert Alan Koeneke James E. Wilson David J. Grabiner .AB no Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. .LP Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. .LP You should have received a copy of the GNU General Public License along with Umoria. If not, see . .AE .NH 1 Introduction .LP The game of \fImoria\fP is a single player dungeon simulation. A player may choose from a number of races and classes when creating a character, and then `run' that character over a period of days, weeks, even months, attempting to win the game by defeating the Balrog which lurks in the deeper levels. .LP The player will begin his adventure on the town level where he may acquire supplies, weapons, armor, and magical devices by bartering with various shop owners. After preparing for his adventure, the player can descend into the dungeons of \fImoria\fP where fantastic adventures await his coming! .LP Before beginning your first adventure, you should read this document carefully. The game of \fImoria\fP is a complicated game, and will require a dedicated player to win. .NH 1 The Character .LP All characters have six main attributes which modify their basic abilities. These six attributes, called \fIstats\fP, are \fIstrength\fP, \fIintelligence\fP, \fIwisdom\fP, \fIdexterity\fP, \fIconstitution\fP, and \fIcharisma\fP. Stats may vary from a minimum of 3 to a maximum of 18. At the highest level, stats are further qualified by a number from zero to one hundred, so that the highest value is actually 18/100. A value of 18/100 can be thought of as equivalent to 19, and 18/00 (not actually used) is equivalent to 18. Because adventurers of interest tend to be better than average characters, \fImoria\fP stats will average about 13, and are further adjusted by race and class. Some races are just naturally better at being certain classes, as will be shown later. .LP In addition to the more visible stats, each character has certain abilities which are mainly determined by his race, class, and level, but are also modified by his stats. The abilities are \fIfighting\fP, \fIthrowing/bows\fP, \fIsaving throw\fP, \fIstealth\fP, \fIdisarming\fP, \fImagical devices\fP, \fIperception\fP, \fIsearching\fP, and \fIinfravision\fP. .LP Characters will be assigned an early history, with money and a social class based on that history. Starting money is assigned based on history, charisma, and somewhat upon the average of a character's stats. A character with below average stats will receive extra money to help him survive the first adventure. .LP Each character will also have physical attributes such as race, height, weight, sex, and a physical description. None of these, except weight, play any part in the game other than to give the player a \*Qfeeling\*U for his character. Weight is used for computing carrying capacity and also for bashing. .LP Finally, each character is assigned \fIhit points\fP based on their race, class, and constitution. Spell casters will also receive \fImana\fP which is expended when casting spells. Mana is based on Wisdom for Priests and Intelligence for Mages. .NH 2 Character Stats .IP "Strength" Strength is important in fighting with weapons and hand to hand combat. A high strength can improve your chances of hitting, and the amount of damage done with each hit. Characters with low strengths may receive penalties. Strength is also useful in tunneling, body and shield bashing, and in carrying heavy items. .IP "Intelligence" Intelligence is the prime stat of a mage, or magician. A high intelligence increases a mage's chances of learning spells, and it also increases the amount of mana a mage has. No spell may be learned by mages with intelligences under 8. Intelligence also modifies a character's chance of disarming traps, picking locks, and using magic devices. .IP "Wisdom " Wisdom is the prime stat of a priest. A high wisdom increases the chance of receiving new spells from a priest's deity, and it also increases the amount of mana a priest has. No spell may be learned by priests with wisdom under 8. Wisdom also modifies a character's chance of resisting magical spells cast upon his person. .IP "Dexterity" Dexterity is a combination of agility and quickness. A high dexterity may allow a character to get multiple blows with lighter weapons, thus greatly increasing his kill power, and may increase his chances of hitting with any weapon and dodging blows from enemies. Dexterity is also useful in picking locks, disarming traps, and protecting yourself from pick pockets. .IP "Constitution" Constitution is a character's ability to resist damage to his body, and to recover from damage received. Therefore a character with a high constitution will receive more hit points, and be more resistant to poisons. .IP "Charisma" Charisma represents a character's personality, as well as physical looks. A character with a high charisma will receive better prices from store owners, whereas a character with a very low charisma will be robbed blind. A high charisma will also mean more starting money for the character. .NH 2 Character Sex .LP You may choose to be either a male or a female character. Only height and weight are affected by a character's sex. Female characters tend to be somewhat smaller and lighter than their male counterparts. No adjustments to stats or abilities are made because of the sex of a character. Female characters start out with slightly more money than male characters to help offset the weight penalty. .NH 2 Character Abilities .LP Characters possess nine different abilities which can help them to survive. The starting abilities of a character are based upon race and class. Abilities may be adjusted by high or low stats, and may increase with the level of the character. .IP "Fighting" Fighting is the ability to hit and do damage with weapons or fists. Normally a character gets a single blow from any weapon, but if his dexterity and strength are high enough, he may receive more blows per round with lighter weapons. Strength and dexterity both modify the ability to hit an opponent. This skill increases with the level of the character. .IP "Throwing/Bows" Using ranged missile weapons and throwing objects is included in this skill. Different stats apply to different weapons, but this ability may modify the distance an object is thrown/fired, the amount of damage done, and the ability to hit a creature. This skill increases with the level of the character. .IP "Saving Throw" A Saving Throw is the ability of a character to resist the effects of a spell cast on him by another person/creature. This does not include spells cast on the player by his own stupidity, such as quaffing a nasty potion. This ability increases with the level of the character, but then most high level creatures are better at casting spells, so it tends to even out. A high wisdom also increases this ability. .IP "Stealth " The ability to move silently about is very useful. Characters with good stealth can usually surprise their opponents, gaining the first blow. Also, creatures may fail to notice a stealthy character entirely, allowing a player to avoid certain fights. This skill is based entirely upon race and class, and will never improve unless magically enhanced. .IP "Disarming" Disarming is the ability to remove traps (safely), and includes picking locks on traps and doors. A successful disarming will gain the character some experience. A trap must be found before it can be disarmed. Dexterity and intelligence both modify the ability to disarm, and this ability increases with the level of the character. .IP "Using Magical Devices" Using a magical device such as a wand or staff requires experience and knowledge. Spell users such as mages and priests are therefore much better at using a magical device than say a warrior. This skill is modified by intelligence, and increases with the level of the character. .IP "Perception" Perception is the ability to notice something without actively seeking it out. This skill is based entirely upon race and class, and will never improve unless magically enhanced. .IP "Searching" To search is to actively look for secret doors, floor traps, and traps on chests. Rogues are the best at searching, but mages, rangers, and priests are also good at it. This skill is based entirely upon race and class, and will never improve unless magically enhanced. .IP "Infravision" Infravision is the ability to see heat sources. Since most of the dungeon is cool or cold, infravision will not allow the player to see walls and objects. Infravision will allow a character to see any warm-blooded creatures up to a certain distance. This ability works equally well with or without a light source. The majority of \fImoria\fP's creatures are cold-blooded, and will not be detected unless lit up by a light source. All non-human races have innate infravision ability. Humans can gain infravision only if it is magically enhanced. .NH 2 Choosing A Race .LP There are eight different races that you can choose from in \fImoria\fP. Some races are restricted as to what profession they may be, and each race has its own adjustments to a character's stats and abilities. .IP "Human " The human is the base character, all other races are compared to him. Humans can choose any class, and are average at everything. Humans tend to go up levels faster than any other race, because of their shorter life spans. No racial adjustments occur to characters choosing human. .IP "Half-Elf" Half-elves tend to be smarter and faster than a human, but not as strong. Half-elves are slightly better at searching, disarming, perception, stealth, and magic, but they are not as good at hand weapons. Half-elves may choose any class. .IP "Elf " Elves are better magicians then humans, but not as good at fighting. They tend to be smarter and faster than either humans or half-elves, and also have better wisdom. Elves are better at searching, disarming, perception, stealth, and magic, but they are not as good at hand weapons. Elves may choose any class except Paladin. .IP "Halfling" Halflings, or Hobbits, are very good at bows, throwing, and have good saving throws. They also are very good at searching, disarming, perception, and stealth; so they make excellent thieves (but prefer to be called burglars...). They will be much weaker than humans, and no good at bashing. Halflings have fair infravision, so they can detect warm creatures at a distance. Halflings can choose between being a warrior, mage, or rogue. .IP "Gnome " Gnomes are smaller than dwarfs, but larger than halflings. They, like the halflings, live in the earth in burrow-like homes. Gnomes are practical jokers, so if they can kill something in a humorous way, so much the better. Gnomes make excellent mages, and have very good saving throws. They are good at searching, disarming, perception, and stealth. They have lower strength than humans so they are not very good at fighting with hand weapons. Gnomes have fair infravision, so they can detect warm creatures at a distance. A gnome may choose between being a warrior, mage, priest, or rogue. .IP "Dwarf " Dwarves are the headstrong miners and fighters of legend. Since dungeons are the natural home of a dwarf, they are excellent choices for a warrior or priest. Dwarves tend to be stronger and have higher constitutions, but are slower and less intelligent than humans. Because they are so headstrong and are somewhat wise, they resist spells which are cast on them. Dwarves also have good infravision because they live underground. They do have one big drawback though. Dwarves are loudmouthed and proud, singing in loud voices, arguing with themselves for no good reason, screaming out challenges at imagined foes. In other words, dwarves have a miserable stealth. .IP "Half-Orc" Half-Orcs make excellent warriors, and decent priests, but are terrible at magic. They are as bad as dwarves at stealth, and horrible at searching, disarming, and perception. Half-Orcs are, let's face it, ugly. They tend to pay more for goods in town. Half-Orcs do make good priests and rogues, for the simple reason that Half-Orcs tend to have great constitutions and lots of hit points. .IP "Half-Troll" Half-Trolls are incredibly strong, and have the highest hit points of any character race. They are also very stupid and slow. They will make great warriors and iffy priests. They are bad at searching, disarming, perception, and stealth. They are so ugly that a Half-Orc grimaces in their presence. They also happen to be fun to run... .NH 3 Race Versus Skills and Stats .LP Stat, hit dice, and experience points per level modifications due to race are listed in the following table. .KS .TS tab(^) center; l 2 n 2 n 2 n 2 n 2 n 2 n 2 n 2 n. ^Str^Int^Wis^Dex^Con^Chr^Hit Dice^Rqd Exp/level .sp Human^0^0^0^0^0^0^10^+0% Half-Elf^\-1^+1^0^+1^\-1^+1^9^+10% Elf^\-1^+2^+1^+1^\-2^+1^8^+20% Halfling^\-2^+2^+1^+3^+1^+1^6^+10% Gnome^\-1^+2^0^+2^+1^\-2^7^+25% Dwarf^+2^\-3^+1^\-2^+2^\-3^9^+20% Half-Orc^+2^\-1^0^0^+1^\-4^10^+10% Half-Troll^+4^\-4^\-2^\-4^+3^\-6^12^+20% .TE .KE Racial abilities as compared to each other, with 1 the lowest, or worst, and 10 the highest, or best, are listed in the following table. .KS .TS tab(^) center; l 1 n 1 n 1 n 1 n 1 n 1 n 1 n 1 l. ^Disarm^Search^Stealth^Percep^Fight^Bows^Save^Infra .sp Human^5^5^5^5^5^5^5^None Half-Elf^6^7^7^6^4^6^6^20 feet Elf^8^9^7^7^3^9^7^30 feet Halfling^10^10^10^10^1^10^10^40 feet Gnome^9^7^9^9^2^8^9^30 feet Dwarf^6^8^3^5^9^5^8^50 feet Half-Orc^3^5^3^2^8^3^3^30 feet Half-Troll^1^1^1^1^10^1^1^30 feet .TE .KE .NH 2 Choosing A Class .LP Once a race has been chosen, you will need to pick a class. Some classes will not be available to certain races, for instance, a Half-Troll cannot become a Paladin. For the first few adventures it is suggested that you run a warrior or rogue. Spell casting generally requires a more experienced player that is familiar with survival techniques. .IP "Warrior" A Warrior is a hack-and-slash character, who solves most of his problems by cutting them to pieces, but will occasionally fall back on the help of a magical device. His prime stats are Strength and Constitution, and a good Dexterity can really help at times. A Warrior will be good at Fighting and Throwing/Bows, but bad at most other skills. .IP "Mage " A Mage must live by his wits. He cannot hope to simply hack his way through the dungeon, and so must therefore use his magic to defeat, deceive, confuse, and escape. A mage is not really complete without an assortment of magical devices to use in addition to his spells. He can master the higher level magical devices far easier than anyone else, and has the best saving throw to resist effects of spells cast at him. Intelligence and Dexterity are his primary stats. There is no rule that says a mage cannot become a good fighter, but spells are his true realm. .IP "Priest " A Priest is a character of holy devotion. He explores the dungeon only to destroy the evil that lurks within, and if treasure just happens to fall into his pack, well, so much more to the glory of his temple! A priest receives his spells from a deity, and therefore does not choose which spells he will learn. He is familiar with magical devices, preferring to call them instruments of god, but Is not as good as a mage in their use. Priests have good saving throws, and make decent fighters, preferring blunt weapons over edged ones. Wisdom and Charisma are the priest's primary stats. .IP "Rogue " A Rogue is a character that prefers to live by his cunning, but is capable of fighting his way out of a tight spot. He is the master of traps and locks, no device being impossible for him to overcome. A rogue has a high stealth allowing him to sneak around many creatures without having to fight, or sneak up and get the first blow. A rogue's perception is higher than any other class, and many times he will notice a trap or secret door before having to search. A rogue is better than a warrior or paladin with magical devices, but still can not rely on their performance. Rogues can also learn a few spells, but not the powerful offensive spells mages can use. A rogue's primary stats are Intelligence and Dexterity. .IP "Ranger " A Ranger is a warrior/mage. He is a good fighter, and the best of the classes with a missile weapon such as a bow. The ranger learns spells much more slowly than a mage, but is capable of learning all but the most powerful spell. Because a ranger is really a dual class character, more experience is required for him to advance. A ranger has a good stealth, good perception, good searching, a good saving throw, and is good with magical devices. His primary stats are Intelligence and Dexterity. .IP "Paladin " A Paladin is a warrior/priest. He is a very good fighter, second only to the warrior class, but not very good at missile weapons. He receives prayers at a slower pace then the priest, but can eventually learn all the prayers. Because a paladin is really a dual class character, it requires more experience to advance him. A paladin lacks much in the way of abilities. He is poor at stealth, perception, searching, and magical devices. He has a decent saving throw due to his divine alliance. His primary stats are Strength and Charisma. .NH 3 Race Versus Class .LP .KS .TS tab(^) center; l 2 ce 2 ce 2 ce 2 ce 2 ce 2 ce. ^Warrior^Mage^Priest^Rogue^Ranger^Paladin .sp Human^Yes^Yes^Yes^Yes^Yes^Yes Half-Elf^Yes^Yes^Yes^Yes^Yes^Yes Elf^Yes^Yes^Yes^Yes^Yes^No Halfling^Yes^Yes^No^Yes^No^No Gnome^Yes^Yes^Yes^Yes^No^No Dwarf^Yes^No^Yes^No^No^No Half-Orc^Yes^No^Yes^Yes^No^No Half-Troll^Yes^No^Yes^No^No^No .TE .KE .NH 3 Class Versus Skills .LP Class abilities as compared to each other, with 1 as the lowest, or worst, and 10 as the highest, or best are shown in the following table. .KS .TS tab(^) center; l 1 c 1 c 1 c 1 c 1 c 1 c 1 c 1 c 1 c l c c c c c c c c c l n n n n n n n n r. ^^^Save^Stea-^^Magic^^^Extra ^Fight^Bows^Throw^lth^Disarm^Device^Percep^Search^Exp/lev .sp Warrior^10^6^3^2^4^3^2^2^+0% Mage^2^1^10^5^6^10^8^5^+30% Priest^4^3^6^5^3^8^4^4^+20% Rogue^8^9^7^10^10^6^10^10^+0% Ranger^6^10^8^7^6^7^6^6^+40% Paladin^9^5^4^2^2^4^2^2^+35% .TE .KE .NH 1 Adventuring .LP After you have created your character, you will begin your \fImoria\fP adventure. Symbols appearing on your screen will represent the dungeon's walls, floor, objects, features, and creatures lurking about. In order to direct your character through his adventure, you will enter single character commands. .LP \fIMoria\fP symbols and commands each have a help section devoted to them. You should review these sections before attempting an adventure. Finally, a description of the town level and some general help on adventuring are included. .NH 1 Symbols On Your Map .LP Symbols on your map can be broken down into three categories: Features of the dungeon such as walls, floor, doors, and traps; objects which can be picked up such as treasure, weapons, magical devices, etc; and creatures which may or may not move about the dungeon, but are mostly harmful to your character's well-being. .LP Some symbols can be in more than one category. Also note that treasure may be embedded in a wall, and the wall must be removed before the treasure can be picked up. .LP It will not be necessary to remember all of the symbols and their meanings. A simple command, the `/', will identify any character appearing on your map. See the section on commands for further help. .LP .nf .KS .TS tab(*) center; c s s s l l l l. Features .sp \&.*A floor space, or hidden trap*1*Entrance to General Store #*A wall*2*Entrance to Armory '*An open door*3*Entrance to Weapon Smith +*A closed door*4*Entrance to Temple ^*A trap*5*Entrance to Alchemy Shop <*A staircase up*6*Entrance to Magic Shop >*A staircase down*:*Obstructing rubble ;*A loose floor stone*\ *An open pit (Blank) %*A mineral vein*@*The character .TE .KE .sp .KS .TS tab(^) center; c s s s l l l l. Objects .sp !^A flask or potion^?^A scroll "^An amulet^[^Hard armor $^Money (Can be embedded)^\e^A hafted weapon &^A chest^]^Misc. armor (^Soft armor^\&_^A staff )^A shield^{^Missile (arrow, bolt, pebble) *^Gems (Can be embedded)^|^Sword or dagger \-^A wand^}^Missile arm (Bow, X-bow, sling) /^A pole-arm^~^Misc \&=^A ring^,^Food s^A skeleton^^ .TE .KE .sp .KS .TS tab(^) center; c s s s l l l l. Creatures .sp a^Giant Ant^A^Giant Ant Lion b^Giant Bat^B^The Balrog c^Giant Centipede^C^Gelatinous Cube d^Dragon^D^Ancient Dragon e^Floating Eye^E^Elemental f^Giant Frog^F^Fly g^Golem^G^Ghost h^Harpy^H^Hobgoblin i^Icky-Thing^I^ j^Jackal^J^Jelly k^Kobold^K^Killer Beetle l^Giant Louse^L^Lich m^Mold^M^Mummy n^Naga^N^ o^Orc or Ogre^O^Ooze p^Human(oid)^P^Giant Human(oid) q^Quasit^Q^Quylthulg r^Rodent^R^Reptile s^Skeleton^S^Scorpion t^Giant Tick^T^Troll u^^U^Umber Hulk v^^V^Vampire w^Worm or Worm Mass^W^Wight or Wraith x^^X^Xorn y^Yeek^Y^Yeti z^Zombie^Z^ $^Creeping Coins^,^Mushroom Patch .TE .KE .NH 1 Commands .LP All commands are entered by pressing a single key. Some commands are capital or control characters, which require you to hold down the shift or control key while pressing another key. As a special feature, control keys may be entered in a single stroke, or in two strokes, with a `^' character first. .LP There are two command sets: the original command set which is the default, and the rogue like command set. The rogue like command is generally more convenient, especially if you don't have a keypad. .LP The following tables summarize the two command sets. Certain commands may be preceded by an optional count, and certain commands must be followed by a direction. These conditions are indicated in the tables by `@' for an optional count, and `~' for a direction. If a particular command requires additional key strokes, then they will be prompted for. .KS .TS tab(^) center; c 1 s 1 s 1 s 1 s 1 s 1 s. Original command summary. .T& l l l l l l s. ^a^Aim and fire a wand^@^B ~^Bash (object/creature) ^b^Browse a book^^C^Change name ^c ~^Close a door^@^D ~^Disarm a trap/chest ^d^Drop an item^^E^Eat some food ^e^Equipment list^^F^Fill lamp with oil ^f^Fire/Throw an item^^G^Gain new magic spells ^i^Inventory list^^L^Locate with map @^j ~^Jam a door with spike^^M^Map shown reduced size ^l ~^Look given direction^@^R^Rest for a period ^m^Magic spell casting^^S^Search Mode @^o ~^Open a door/chest^@^T ~^Tunnel in a direction ^p^Pray^^V^View scoreboard ^q^Quaff a potion^^\&=^Set options ^r^Read a scroll^^?^Command quick reference @^s^Search for trap or door^^{^Inscribe an object ^t^Take off an item^@^\- ~^Move without pickup ^u^Use a staff^^. ~^Run in direction ^v^Version, credits and manual^^/^Identify a character ^w^Wear/Wield an item^^CTRL-K^Quit the game ^x^Exchange weapon^@^CTRL-P^Repeat the last message ^<^Go up an up staircase^^CTRL-X^Save character and quit ^>^Go down a down staircase^@^~^for movement .TE .KE .KS .TS tab(^) center; c 1 s 1 s 1 s 1 s 1 s 1 s. Rogue like command summary. .T& l l l l l l s. ^c ~^Close a door^^C^Character description ^d^Drop an item^@^D ~^Disarm a trap/chest ^e^Equipment list^^E^Eat some food @^f ~^Force/bash item/monster^^F^Fill lamp with oil ^i^Inventory list^^G^Gain new magic spells ^m^magic spell casting^^M^Map shown reduced size @^o ~^Open a door/chest^^P^Peruse a book ^p^Pray^^Q^Quit the game ^q^Quaff a potion^@^R^Rest for a period ^r^Read a scroll^@^S ~^Spike a door @^s^Search for trap or door^^T^Take off an item ^t^Throw an item^^V^View scores ^v^Version, and manual^^W^Where: locate self ^w^Wear/Wield an item^^X^Exchange weapon ^x ~^Examine surroundings^^Z^Zap a staff ^z^Zap a wand^^#^Search Mode ^\&=^Set options^^<^Go up an up staircase ^/^Identify a character^^>^Go down a down stair @^CTRL-P^Previous message review^^{^Inscribe an object @^\- ~^Move without pickup^^?^Type this page @^CTRL ~^Tunnel in a direction^^CTRL-X^Save game and exit @^SHFT ~^Run in direction^@^~^for movement .TE .KE .NH 2 Special keys. .LP Certain commands may be entered at any time input is accepted. The special character control-R, entered as a single key stroke, will always refresh the screen. This may be used at any prompt for input, and is otherwise ignored. .LP If you are playing on a UNIX or similar system, then there are some additional special characters used by \fImoria\fP. The special character control-C will interrupt \fImoria\fP, and ask if you really want to die and quit the game. If you choose not to die, \fImoria\fP merely continues as before, except that resting, running, repeated commands, etc will be terminated. You can suspend the game with control-Z, and return to the original command shell. In this case, \fImoria\fP is not terminated, and may be restarted at any time from the shell. Alternatively, the special command `!' is available to run any normal shell command. When it is complete, \fImoria\fP will restart. .LP For many input requests or queries, the special character ESCAPE will abort the command. For the \*Q\-more\-\*U message prompts, any of SPACE, ESCAPE, RETURN (control-m), or LINEFEED (control-j) can be used to continue after pausing to read the displayed message. .LP It is possible to give control character commands in two key stroke, by typing a `^' followed by the appropriate letter of the alphabet. This is useful when running \fImoria\fP in circumstances where control characters are intercepted by some external process, or by the operating system. .NH 2 Direction. .LP For the original style command set, a direction is given by a digit which is in the appropriate orientation on your keypad. For the rogue like command set, a direction is given by one of the letters `hykulnjb'. Again, the relative position of the keys on the keyboard gives a clue as to the direction. The digit `5' for the original commands, and the period `.' for rogue like commands, is a null direction indicator. This is only allowed in a movement command (to stay in one place) or in a look command (to look in all directions). .RS .KS .TS tab(^); c s s n n n. Original Directions .sp \0\\\\\&^\0|\&\0^\0\&/ 7^8^9 .sp \-\0 4^ ^6\&\0\0\- .sp 1^2^3 \0/\0\&^\0|\&\0^\0\&\\\\\& .TE .KE .KS .TS tab(^); c s s n n n. Rogue-like Directions .sp \0\\\\\&^\0|\&\0^\0\&/ y\&^k\&^u\& .sp \-\0 h\&^ ^l\&\0\0\- .sp b\&^j\&^n\& \0/\0\&^\0|\&\0^\0\&\\\\\& .TE .KE .RE .LP Movement is accomplished by specifying a direction immediately. Simply press the appropriate key and you character will move one step in that direction. You can only move onto and through floor spots, and only if they contain no creatures or obstructing objects such as a closed door. .LP Other commands that require a direction will prompt for it. .LP Moving your character one step at a time can be time consuming and boring, so a faster method has been supplied. For the original style command set, by using the Run command `.', you may move in a direction until something interesting happens. For instance, by pressing the period key `.' followed by the direction 8, your character would continue to move up the screen, only coming to a stop after at least one condition is satisfied. For the rogue like command set, typing a shifted directional letter will move you in that direction until something interesting happens. The stopping conditions are described more completely in the run command description below. .NH 2 Command counts. .LP Some commands can be executed a fixed number of times by preceding them with a count. Counted commands will execute until the count expires, or until you type any character, or until something significant happens, such as being attacked. Thus, a counted command doesn't work to attack another creature. While the command is being repeated, the number of times left to be repeated will flash by on the command line at the bottom of the screen. .LP To give a count to a command in the rogue like mode, type the number in digits, then the command. A count of zero defaults to a count of 99. .LP To give a count to a command in the original mode, type a `#', followed by the digits. To count a movement command (which is itself a digit), type a space after the number, and you will then be prompted for the command. .LP Counted commands are very useful for searching or tunneling, as they automatically terminate on success, or if you are attacked. You may also terminate a counted command, or a Run command, by typing any character. This character is ignored, but it is safest to use a SPACE or ESCAPE which are always ignored as commands. .NH 2 Selection of objects. .LP Many commands will also prompt for a particular object to be used. For example, the command to read a scroll will ask you which of the scrolls that you are carrying that you wish to read. In such cases, the selection is made by typing a letter of the alphabet; if you are selecting from your pack, you may also type a digit to select the item whose inscription is that digit. The prompt will indicate the possible letters, and will also allow you to type the key `*', which causes all of the available options to be described. .LP The particular object may be selected by an upper case or a lower case letter. If lower case or a digit is used, the selection takes place immediately. If upper case is used, then the particular option is described, and you are given the option of confirming or retracting that choice. Upper case selection is thus safer, but requires an extra key stroke. .NH 2 Command descriptions .LP In the following command descriptions, the original style key is given. If the rogue like key for that command is different, then it will be shown inside the braces following the command name. .IP "B - Bash. {f - force}" The bash command includes breaking open doors and chests, or bashing an opponent. Your bashing ability increases with weight and strength. In addition, when bashing an opponent, you will either perform a body bash, or, if wielding a shield, perform a shield bash which is more effective. .sp Bashing a door can throw you off balance, but this will not generally be a problem. Doors that have been jammed closed with spikes can only be opened by bashing. Locked doors may also be bashed open. Bashing a door open will permanently break it. .sp Bashing a creature affects both you and the opponent. Depending on your dexterity, you may or may not be thrown off balance allowing free moves to your opponent. If the bash is successful, your opponent may be thrown off balance, thus giving you some free hits or a chance to run. Huge creatures such as ancient dragons will be difficult or impossible to bash successfully. .sp A player automatically performs a shield bash instead of a body bash, if he is currently wearing a shield. A shield bash adds the damage of a shield to that of the bash, so it is more effective. Size and material both affect the damage that a shield will do. .sp You can apply a count to this command, but if you are thrown off balance, the count will be reset straight away. .IP "C - Print character (to screen or file)." This command allows the player to either display his character on the terminal screen, or to print an entire character info listing to a file. The character's history, equipment, and inventory list are also included if you chose to print it to a file. .IP "D - Disarm a trap." You can attempt to disarm floor traps, or trapped chests. If you fail to disarm a trap, there is a chance that you blunder and set it off. You can only disarm a trap on a chest after finding it with the search command. This command can have a count. .IP "E - Eat some food." A character must eat occasionally to remain effective. As a character grows hungry, a message will appear at the bottom of the screen saying \*QHungry\*U. If a character remains hungry long enough, he will become weak, eventually start fainting, and finally die of starvation. .IP "F - Fill a lamp or lantern with oil." If your character is currently using a lamp for light, and if he has a flask of oil in inventory, he may refill the lamp by using this command. A lamp is capable of a maximum of 15000 turns of light, and each flask has 7500 turns of oil contained in it. .IP "G - Gain new spells." To actually learn new spells, you must use this command. When you are able to learn some spells, the word \*QStudy\*U will appear on the status line at the bottom of the screen. Mages, rogues, and rangers must have the magic books containing new spells to be able to learn them. Priests and Paladins are given their prayers by their gods, and hence do not need a holy book before learning the prayers in it. They do need the book in order to use the prayers. .IP "L - Location on map. {W - where}" The location command allows you to look at all parts of the current dungeon level. The displayed view of the dungeon is shifted to bring your current position as close to the center as possible. You may then shift the displayed map in any of the eight possible directions. Each shift moves your view point by one half screen. The top line displays a map section number, each map section having a height and width one half that of the display, and indicates the direction of the display from your current position. If you exit this command while you are not on the display, then the display is centered again. .IP "M - Map shown reduced size." This command will show the entire map, reduced by a factor of nine, on the screen. Since nine places map into every character on the screen, only the major dungeon features will be visible. This is especially useful for finding where the stairs are in relation to your current position. It is also useful for identifying unexplored areas. .IP "R - Rest for a number of turns." You may rest one turn with the null movement command. Resting for longer periods of time is accomplished by using the Rest command, followed by the number of turns you want to rest your character. Resting will continue until the specified duration has expired, or something to wake the character happens, such as a creature wandering by, or getting hungry, or some disability like blindness expiring. It is sometimes a good idea to rest a beat-up character until he regains some of his hit points, but be sure to have plenty of food if you rest often. .sp If you have accidentally entered in a rest period too large, or change your mind about the resting period, you may wake your character up by typing any character. Space is best, since if the rest ends just before the character is typed, the space is ignored as a command. .sp It is also possible to rest by typing the count first, and using either the Rest or the null movement command. .sp If you type `*' for the rest count, your character will rest until both hp and mana reach their maximum values. As above, you will immediately stop resting if anything interesting happens. .IP "S - Search mode toggle. {#}" The Searching toggle will take you into and out of search mode. When first pressed, the message \*QSearching\*U will appear at the bottom of the screen. You are now taking two turns for each command, one for the command and one turn to search. This means that you are taking twice the time to move about the dungeon, and therefore twice the food. If a creature should happen by or attack you, search mode will automatically shut off. You may also turn off search mode by again pressing the `S' {or #} key. .IP "T - Tunnel through rock. {control-}" Tunneling (Mining) is a very useful art. There are four kinds of rock present in the dungeons of \fImoria\fP: Permanent Rock, Granite Rock, Magma Intrusion, and Quartz Veins. Permanent Rock is exactly that, permanent. Granite is very hard, therefore hard to dig through, and contains no valuable metals. Magma and Quartz veins are softer and sometimes bear valuable metals and gems, shown as a `$' or a `*' character. You can tell if the metal or gems are embedded into the wall by trying to move onto them. If you can't move over them, you'll have to dig them out. There is an option which causes magma and quartz to be displayed differently than other rock types. .sp Tunneling can be VERY difficult by hand, so when you dig be sure to wield either a shovel or a pick. Magical shovels and picks can be found which allow the wielder to dig much faster than normal, and a good strength also helps. .sp Tunneling can have a count. .IP "V - View scoreboard." This command will display the contents of the score board on the screen. On a multiuser system, typing `V' again will show only those scores from the score board that are yours. .IP "a - Aim a wand. {z - zap}" Wands must be aimed in a direction to be used. Wands are magical devices and therefore use the Magical Devices ability of the player. They will either affect the first object/creature encountered, or affect anything in a given direction, depending upon the wand. An obstruction such as a door or wall will generally stop the effects of a wand from traveling further. .IP "b - Browse a book. {P - peruse}" You can only read a book if you are of its realm. Therefore a magic user could read a magic book, but not a holy book. Warriors will not be able to read either kind of book. When the browse command is used, all of the spells or prayers contained therein are displayed, along with information such as their level, the amount of mana used up in casting them, and whether or not you know the spell or prayer. There are a total of 31 different magical spells in four books, and 31 different prayers in four books. .IP "c - Close a door." Nonintelligent and certain other creatures will not be able to open a door. Therefore shutting doors can be a life saver. You must be adjacent to an open door, and you cannot close broken doors. Bashing a door open will break it. .IP "d - Drop an object from your inventory." You can drop an object onto the floor beneath you if that floor spot does not already contain an object. Doors and traps are considered objects in this sense. If you have several objects of the same kind, you will be prompted for dropping one or all of them. It is possible to directly drop things which you are wielding or wearing. .IP "e - Display a list of equipment being used." Use the Equipment command to display a list of objects currently being used by your character. Each object has a specific place where it is placed, and that only one object of each type may be used at any one time, excepting rings of which two can be worn, one on each hand. .IP "f - Fire/Throw an object/use a missile weapon. {t - throw}" You may throw any object carried by your character. Depending upon the weight of an object, it may travel across a room or drop down beside you. If you throw an object such as an arrow, only one will be used at a time. .sp If you throw at a creature, your chance of hitting the creature is determined by your plusses to hit, your ability at throwing, and the object's plusses to hit. Once the creature is hit, the object may or may not do any actual damage to it. Certain objects in the dungeon can do great amounts of damage when thrown, but it's for you to figure out the obscure ones. Oil flasks are considered to be lit before thrown; therefore, they will do fire damage to a creature if they hit it. .sp To use a bow with arrows, simply wield the bow and throw the arrows. Extra plusses to damage and hitting are gained by wielding the proper weapon and throwing the corresponding ammo. A heavy crossbow with bolts for example, is a killer... .IP "i - Display a list of objects being carried." This command displays a list of all objects being carried, but not currently in use. You may carry up to 22 different kinds of objects, not including those in your equipment list. Depending upon your strength, you will be able carry many identical objects before hitting your weight limit. .IP "j - Jam a door with an iron spike. {S - spike}" Most humanoid and many intelligent creatures can simply open a closed door, and can eventually get through a locked door. Therefore you may spike a door in order to jam it. Each spike used on a door will increase its strength, although the more spikes you add, the less effect each additional spike has. It is very easy to jam a door so much as to make it impossible for your character to bash it down, so spike doors wisely. The bigger a creature is, the easier it can bash a door down. Therefore twenty or more spikes might be necessary to slow down a dragon, where one spike would slow down a kobold. This command can be counted. .IP "l - Look in a direction. {x - examine}" The Look command is useful in identifying the exact type of object or creature shown on the screen. Also, if a creature is on top of an object, the look command will describe both. You can see creatures and objects up to 200 feet away (20 spaces). You may freely use the Look command without the creatures getting a move on you. .sp Looking in a particular direction sees everything within a cone of vision which just overlaps the cones of the two adjacent directions. Looking with the null direction `5' (or `.') sees everything which there is to be seen. .sp You are also able to access you monster memories with this command. If you see a creature, you are prompted to ask if you wish to see a short paragraph of information about your experiences with that creature. See also the section on being attacked. .IP "m - Cast a magic spell." To cast a spell, a character must have previously learned it, and must also have in the inventory a magical book from which the spell may be read. Each spell has a chance of failure which starts out fairly large but decreases as a character gains levels. If a character does not have enough mana, the chance of failure is greatly increased, and he gambles on losing a point of constitution. You will be prompted for confirmation before trying to cast a spell when you don't have enough mana. Since a character must read the spell from a book, he cannot be blind or confused when casting a spell, and there must be some light present. .IP "o - Open a door, chest, or lock." To open an object such as a door or chest, you must use the Open command. If the object is locked, the Open command will attempt to pick the lock, based on your ability at disarming. If an object is trapped and you open it, the trap will be set off. This command can be counted, because you may need several tries to get a locked door or chest open. .IP "p - Read a prayer." To pay effectively, a character must have learned the prayer, and must also have in the inventory a holy book from which the prayer may be read. Each prayer has a chance of being ignored which starts out fairly large but decreases as a character gains levels. If a character does not have enough mana, the chance of failure is greatly increased, and he gambles on losing a point of constitution. You will be prompted for confirmation before trying to pray when you don't have enough mana. Since a character must read the prayer from a book, he cannot be blind or confused when praying, and there must be some light present. .IP "q - Quaff a potion." To drink a potion use the Quaff command. A potion affects the player in some manner. The effects of the potion may be immediately noticed, or they may be subtle and unnoticed. .IP "r - Read a scroll." To read a scroll use the Read command. Most scroll spells either affect the player or the area around the player; a few cases such as identify scrolls act on other objects. Two scrolls, the identify scroll and the recharge scroll, have titles which can be read without setting them off, and by pressing ESCAPE can be saved for future use. .IP "s - Search general area one turn." The Search command can be used to locate hidden traps and secret doors about the player. More than a single turn of searching will be required in most cases. You should always search a chest before trying to open it because they are generally trapped. This command can be counted, which is useful if you are really sure of finding something eventually. A counted search ends as soon as anything is found. .IP "t - Take off a piece of equipment. {T}" Use the Take Off command to remove an object from use, and return it to your inventory. Occasionally you will run into a cursed item which cannot be removed. Cursed items are always bad, and can only be taken off after removing the curse. .IP "u - Use a staff. {Z - Zap}" The Use command will activate a staff. Like scrolls, most staffs have an area effect. Because staffs are generally more powerful than most other items, they are also harder to use correctly. .IP "v - Display current version of game." The Version command displays the credits for the current version of \fImoria\fP. .IP "w - Wear or wield an item being carried." To wear or wield an object in your inventory, use the Wear/Wield command. If another object is already in use for the same function, it is automatically removed first; if you are wearing two rings, you are given a choice of which one to remove. An object's bonuses cannot be gained until it is worn or wielded. .IP "x - Exchange primary and secondary weapons. {X}" A secondary weapon is any weapon which may be needed often. Instead of searching through your inventory, you may use the exchange command to keep the weapon ready. For instance, if you wanted to use your bow most of the time, but needed a sword for close combat, you could wield your sword, use the exchange command to make it the secondary weapon, then wield your bow. If the sword was suddenly needed, simply use the exchange command to switch between the bow and the sword. .IP "/ - Identify a character shown on screen." Use the identify command to find out what a character displayed on the screen stands for. For instance, by pressing `/.', you can find out that the `.' stands for a floor spot. When used with a creature, the identify command will tell you only what class of creature the symbol stands for, not the specific creature; therefore, use the look command for this information. .sp If you identify the character for a creature in your monster memory, you are also prompted to ask if you wish to see a paragraph of information on those creatures identified by the given character. Several creatures may be identified in this way. Typing ESCAPE after the paragraph for any creature will abort back to command level. See also the section on being attacked. .IP "? - Display a list of commands." The ? command displays a quick reference help page on the screen. .IP "\- - Move without pickup." This is followed by a move command, and causes you to move over any object without picking it up. You can associate a count with this command. .IP "= - Set options." This is a free move, to set various \fImoria\fP options. The available options are: .IP " (1)" Cut known corners when running. This is on by default, and the only reason for switching it off would be if you had the search flag on and wished to look for doors in the extremity of every corner. .IP " (2)" Examine potential corners when running. This is on by default, and allows you to run along an unknown curving corridor. If, however, you are running from a creature, you may wish to switch this option off, because the creature will cut the corner. .IP " (3)" Print self during a run. This is off by default, which gives faster screen updating. .IP " (4)" Stop when map sector changes. This is off by default, but can be switched on if you wish to stop running whenever a new part of the dungeon appears in view. .IP " (5)" Treat open doors as empty space while running. This is off by default, in which case you stop whenever you run up to an open door. .IP " (6)" Prompt to pick up objects. This is off by default, in which case stepping over an object automatically causes you to pick it up. With the option on, you get prompted in all such cases with a description of the object to see if you really want to take it. .IP " (7)" Rogue like command set. This option controls the command set in use. It is off by default. .IP " (8)" Show weights in inventory. This is off by default: switching it on causes the inventory and equipment listings to include the weight of all objects. This may be useful to know if your pack is getting too heavy. .IP " (9)" Highlight and notice mineral seams. This is off by default. Switching it on causes quartz and magma to be displayed as `%' instead of `#'; also, it causes the look command to treat them as interesting objects. This is handy when mining. Setting this option does not immediately highlight all minerals, but only those which are subsequently displayed. To display all minerals, just move the map around a bit with the `Where' (or `Locate') command. .IP " (10)" Beep for invalid character. This is on by default. When on, the program will beep for most invalid characters, such as trying to choose a spell that you haven't learned yet. When off, there are no such beeps. .IP " (11)" Display rest/repeat counts. This is on by default. When on, the program will progressively display the remaining turns left while resting, and for repeated commands. For those trying to play over a 2400 bps or less connection, or for those playing on very slow microcomputers, turning this off will make resting and repeated commands work much faster. .IP The setting of all these options persist in your savefile, even after you die. .IP "^P - Previous message." The Control-P command will redisplay the last message printed on the message line at the top of your screen. A second such command will display all of the saved messages. You may also give this command a count to specify the number of previous messages to display. At present, only 22 messages are saved. .IP "^K - Quit the game without saving. {Q}" To exit the game without saving your character (i.e. kill him/her) use the Control-K command. Once exited in this manner, your character is nonrecoverable. .IP "^X - Save your character and exit the game." To save your game so that it can be restarted later, use the Control-X command. Save files will also be generated if the game crashes due to a system error. When you die, a reduced save file is produced containing only your monster memory, and your option settings. .IP "{ - Inscribe an object." This command can be used to inscribe any short string on an object. Inscriptions are limited to twelve characters. The inscription applies only to the particular object, it is not automatically transferred to all similar objects. Under certain circumstances, \fImoria\fP will itself inscribe objects: if they have been discovered to be cursed or enchanted, or if they have been sampled without being identified. In this last case, \fImoria\fP does in fact carefully inscribe every such item. .sp If the inscription on an item is a single digit, that digit can be used to refer to it when using, wearing, or wielding an item from your pack. For example, if you keep a pick in your pack with the inscription 1, you can switch to the pick by wielding item 1 without checking your full inventory list to find out which item the pick is. .IP "! - Shell out of game." Use the Shell command `!' to temporarily exit the game to execute UNIX or MSDOS commands. You may reenter the game by typing exit to end the spawned process. This is not implemented in the Macintosh version. .IP "< - Go up an up staircase." If you move onto an up staircase you may use the `<' command to go up one level. There is always one staircase going up on every level except for the town level (this does not mean it's easy to find). Going up a staircase will always take you to a new dungeon area except for the town level, which remains the same for the duration of your character. .IP "> - Go down a down staircase." If you are on top of a down staircase you may use the `>' command to go down one level. There are always two or three staircases going down on each level, except the town level which has only one. Going down will always take you to a new dungeon area. .IP ". - Move in direction. {shift}" The Run command will move you in the indicated direction until either you have to make a choice as between two directions, or something interesting happens. There are options which determine behavior at corners, and at screen boundaries. More precisely, the conditions which stop a run are as follows: .IP (1) A creature appears on the screen, one already on the screen moves, or a creature attacks you or casts a spell at you. .IP (2) You move next to an object, or a feature such as a door or trap. .IP (3) You come to the end of open space, or the end of a passage, or a junction of passages, or a hole in a wall. .IP (4) Anything typed during a run causes the run to stop. The character causing this to occur is ignored. It is best to use a space, which is ignored as a command, just in case the run stops just before you type the character. .IP (5) Various changes of state, such as recovery from fear or loss of heroism, will stop a run. .sp Corners are more complex. A corner allows a choice between adjacent rectangular and diagonal directions. If you can see walls which ensure that the diagonal gives a faster traversal, then action is determined by the \*Qcut corners\*U options. If it is set, then you move diagonally through the corner. This gives you maximum speed (as is nice if you are fleeing a hidden creature). On the other hand, this option should not be set if you want more careful coverage (as when you are searching) so that you take two moves through the corner. .sp At a potential corner, where walls are not yet visible ahead of the rectangular direction, the \*Qexamine corners\*U option is considered. If set, you will move straight into the corner, which will light up all the corner and so determine where you can go from there. This allows you to follow corners in new passages. If the option is not set, you stop. This allows highly cautious running where you want to stop at all potential choice points. .sp If you move off the screen while running, then a new section of the dungeon is displayed and the run continues. However, if the \*Qstop when map changes\*U option is set, you will stop. Again, this is an option for nervous players; after all, there may be a dragon on the new screen. moria-5.6.debian.1/doc/pronounc0000644000175000017500000000477105613574143014537 0ustar pjbpjb I used to pronounce the name as muh-RYE-uh. This is probably because I have heard a song "They call the wind Mariah!" which uses this pronounciation. This song is from the musical "Paint Your Wagon" by Lerner and Lowe. This game is based on the books by J. R. R. Tolkien, though, so I got out my books and looked it up. Below is the result of my investigation. -- "The Return of the King", Part Three of the trilogy "The Lord of the Rings" Appendix F, section II: On Translation, paragraph 19 "But Moria is an Elvish name, and given without love; for the Eldar, though they might at need, in their bitter wars with the Dark Power and his servants, contrive fortresses underground, were not dwellers in such places of choice." section I: The Languages and Peoples of the Third Age, subsection Of the Elves, paragraph 2 "Of the Eldarin tongues two are found in this book: the High-elven or Quenya, and the Grey-elven or Sindarin." paragraph 4 "The Exiles, dwelling among the more numerous Grey-elves, had adopted the Sindarin for daily use; and hence it was the tongue of all those Elves and Elf-lords that appear in this history." Appendix E section I: Pronunciation of Words and Names subsection Consonants "I initially before another vowel has the consonantal sound of y in you, yore in Sindarin only: as in Ioreth, Iarwain." "R represents a trilled r in all positions; the sound was not lost before consonants (as in English part). The Orcs, and some Dwarves, are said to have used a back or uvular r, a sound which the Eldar found distasteful." subsection Vowels, paragraph 1 "That is, the sounds were approximately those represented by i, e, a, o, u in English machine, were, father, for, brute, irrespective of quantity." subsection Vowels, paragraph 4 "In Sindarin long vowels in stressed monosyllables are marked with the circumflex, since they tended in such cases to be specially prolonged; so in du^n compared with Du'nadan." [Note: see ia^ below] subsection Stress, paragraph 1 "In words of two syllables it falls in practically all cases on the first syllable." -- "The Silmarillion" Appendix: Elements in Quenya and Sindarin Names "mor 'dark' in Mordor, Morgoth, Moria, etc." "ia^ 'void, abyss' in Moria" [Note: ia^ apparently is a single syllable because of the circumflex over the a.] Hence, the correct pronounciation appears to be MOR-yah (trill the r) Alternatively, MOR-ee-ah might be acceptable if the ee sound is kept short, and you don't have to trill the r if you feel uncomfortable doing it. moria-5.6.debian.1/doc/moria.man0000644000175000017500000000673005613574144014553 0ustar pjbpjb MORIA(6) GAMES AND DEMOS MORIA(6) NAME moria - a dungeon game SYNOPSIS moria [ -o ] [ -r ] [ -s ] [ -S ] [ -n ] [ -w ] [ savefile ] DESCRIPTION Moria plays a dungeon game with you. It lets you generate a character, lets you buy equipment, and lets you wander in a fathomless dungeon while finding treasure and being attacked by monsters and fellow adventurers. Typing ? gives you a list of commands. The ultimate object of moria is to kill the Balrog, which dwells on the 50th level of the dungeon, 2,500 feet under- ground. Most players never even reach the Balrog, and those that do seldom live to tell about it. For a more complete description of the game, read the docu- ment The Dungeons of Moria. By default, moria will save and restore games from a file called moria.save in your home directory. If the environ- ment variable MORIA_SAV is defined, then moria will use that file name instead of the default. If MORIA_SAV is not a complete path name, then the savefile will be created or restored from the current directory. You can also expli- citly specify a savefile on the command line. If you use the -n option, moria will create a new game, ignoring any savefile which may already exist. This works best when a savefile name is specified on the command line, as this will prevent moria from trying to overwrite the default savefile (if it exists) when you try to save your game. You move in various directions by pressing the numeric keypad keys, VMS-style. If you specify -r, you move the same way you do in rogue(6). You can also specify -o to force the VMS-style command set. These options will over- ride defaults stored in the savefile. If these options are given multiple times, only the last one will take effect. If you specify -s, moria prints all of the scores in the score file and exits. On a multiuser system, if you specify -S, moria prints prints only those scores belonging to you and then exits. If you specify -w, moria will start up in wizard mode. You can resurrect a dead character by using this option when starting the game. Resurrected characters are teleported to the town level and given zero hitpoints. Wizard mode is Local Last change: 1 MORIA(6) GAMES AND DEMOS MORIA(6) intended for debugging the game, and for experimenting with new features. Any other use is considered cheating. Games played with wizard mode are not scored. AUTHORS The original version of Moria was written in VMS/Pascal by Robert Alan Koeneke, Jimmey Wayne Todd, Gary McAdoo, and others at the University of Oklahoma. This version was written by Jim Wilson at the University of California, Berkeley, and released with minor revisions by David Gra- biner at Harvard University. BUGS A suspended game that gets a hangup signal will die without creating a save file. Rerolling with a % at the class prompt not implemented. For a more comprehensive list, see the ERRORS file in the source distribution. Local Last change: 2 moria-5.6.debian.1/doc/where.inf0000644000175000017500000001056311074752766014564 0ustar pjbpjb This is the information from the FAQ on getting a copy of Moria. It is current as of 10/13/08. A working version of UMoria 5.5.2 is now available for the PC; it's also available at the main Moria archive, but this URL is more likely to work. http://www3.ns.sympatico.ca/dmswaine/m552-386.zip A version with a few additional features is available at: http://www.geocities.com/lhelgeland/umoria.html Linux sources (designed for Debian, but they also work on Red Hat at least) are at http://packages.debian.org/moria Sources for FreeBSD are at http://www.freebsd.org/cgi/ports.cgi?query=Moria&stype=all. UMoria 5.5.2 is available for Mac OS X (search for "Moria") http://fink.sourceforge.net Umoria 5.5.2 has been ported to the PalmOS at http://roguelike-palm.sourceforge.net/kMoria/index.php The main Moria archive has moved to a new home; it makes files available by anoymous FTP: ftp://ftp.greyhelm.com/pub/Games/Moria Three near-complete mirrors are available. ftp://ftp.funet.fi/pub/unix/games/moria/ ftp://ftp.planetmirror.com/pub/roguelike/moria/ (in Australia) (The third is a slow connection; please do not use it if you can get to another site.) http://www.piratehaven.org/~beej/moria/mirror/Games/Moria/ Use the pathnames listed below, ignoring the leading /pub/Games/Moria. Some files on the mirrors may be compressed with different compression programs such as gzip. The documentation, including the official manual and this FAQ, is available at http://www2.ecst.csuchico.edu/~beej/moria/ The sources for Umoria 5.5.0 were also posted to comp.sources.games, so they should be available (in compressed shar form) on any site which archives comp.sources.games, such as ftp.uu.net. The following paths give the structure of the Moria archive; they will probably be maintained when the archive moves somewhere else. /pub/Games/Moria/[machine name] Executables for the Amiga, Atari ST, IBM PC, and Mac; look at the README files in these directories for more information. Some of these files may need to be transferred in binary mode; type "binary" before transferring the files. KSU has both color and monochrome executables for the IBM PC. European users can also get Mac binaries from jyu.fi, in a file /maclib/game/moria.sit.bin. /pub/Games/Moria/pc/80386-5.5.2/m552-386.zip This is the 5.5.2 executable for the PC. /pub/Games/Moria/source/um5.5.2.tar.Z A compressed tar file containing the entire source, for use on any system; if you have tar on your system, this is probably the file that you want. (If you don't have compress, you can FTP it as well; it is /pub/Games/Moria/compress.tar.) This file must be transferred in binary mode; type "binary" before getting the file. Once you have the tar.Z file, type "zcat um5.5.2.tar.Z | tar xf -" to extract the files, and read the README files for help in installing. /pub/Games/Moria/pc/zip-arc/mor55src.zip A ZIP file containing the source. /pub/Games/Moria/pc/zip-arc/wmoria10.zip_exec /pub/Games/Moria/pc/zip-arc/wmoria10.zip_source Source and Modula-2 executables for Wmoria 1.0, a port of Umoria 5.5.0 to Windows 3.1. /pub/Games/Moria/patches Patches for upgrading Moria from one version the the next version, and for modifications. /pub/Games/Moria/XMoria/xm1.07.tar.Z The source to Moria for X Windows. /pub/Games/Moria/doc The documentation for Moria 5.5, including the official documentation, the FAQ file, and a complete monster list. /pub/Games/Moria/pc/mono5.5 The auxilliary files are in this directory; you may need them if you have an executable without them. /pub/Games/Angband The source to Angband for UNIX, and source and executable for the PC and Mac. /pub/Games/Moria/boss The source distribution, in Pascal, for BOSS. /pub/Games/Moria/vms The source discribution, in Pascal, for VMS Moria 4.8 and 5.0. Umoria 5.x will also work on VMS machines. (Note that VMS Moria 5.0 is not a version of Umoria 5.x.) /pub/Games/Moria/unofficial Other unofficial modifications of Moria, including JAMoria, the druid version for the PC, and the sources for Morgul and Pmoria. /pub/Games/Moria/utils/calchits.shar.Z A program for calculating the average damage done with various weapons, allowing you to compare them. VMS sources for Imoria are available on ubvms.cc.buffalo.edu, in a directory /maslib/games/imoria. VMS Moria 4.8 and 5.0 sources are also there. Linux code for Imoria is available from http://www.angelfire.com/games3/imoria/imoria.html. moria-5.6.debian.1/doc/moria2.txt.orig0000644000175000017500000016201705613574150015636 0ustar pjbpjb The Dungeons of Moria Page 18 Rock, Granite Rock, Magma Intrusion, and Quartz Veins. Per- manent Rock is exactly that, permanent. Granite is very hard, therefore hard to dig through, and contains no valu- able metals. Magma and Quartz veins are softer and some- times bear valuable metals and gems, shown as a `$' or a `*' character. You can tell if the metal or gems are embedded into the wall by trying to move onto them. If you can't move over them, you'll have to dig them out. There is an option which causes magma and quartz to be displayed dif- ferently than other rock types. Tunneling can be VERY difficult by hand, so when you dig be sure to wield either a shovel or a pick. Magical shovels and picks can be found which allow the wielder to dig much faster than normal, and a good strength also helps. Tunneling can have a count. V - View scoreboard. This command will display the contents of the score board on the screen. On a multiuser system, typing `V' again will show only those scores from the score board that are yours. a - Aim a wand. {z - zap} Wands must be aimed in a direction to be used. Wands are magical devices and therefore use the Magical Devices abil- ity of the player. They will either affect the first object/creature encountered, or affect anything in a given direction, depending upon the wand. An obstruction such as a door or wall will generally stop the effects of a wand from traveling further. b - Browse a book. {P - peruse} You can only read a book if you are of its realm. Therefore a magic user could read a magic book, but not a holy book. Warriors will not be able to read either kind of book. When the browse command is used, all of the spells or prayers contained therein are displayed, along with information such as their level, the amount of mana used up in casting them, and whether or not you know the spell or prayer. There are a total of 31 different magical spells in four books, and 31 different prayers in four books. c - Close a door. Nonintelligent and certain other creatures will not be able to open a door. Therefore shutting doors can be a life saver. You must be adjacent to an open door, and you cannot close broken doors. Bashing a door open will break it. d - Drop an object from your inventory. You can drop an object onto the floor beneath you if that floor spot does not already contain an object. Doors and traps are considered objects in this sense. If you have several objects of the same kind, you will be prompted for The Dungeons of Moria Page 19 dropping one or all of them. It is possible to directly drop things which you are wielding or wearing. e - Display a list of equipment being used. Use the Equipment command to display a list of objects currently being used by your character. Each object has a specific place where it is placed, and that only one object of each type may be used at any one time, excepting rings of which two can be worn, one on each hand. f - Fire/Throw an object/use a missile weapon. {t - throw} You may throw any object carried by your character. Depend- ing upon the weight of an object, it may travel across a room or drop down beside you. If you throw an object such as an arrow, only one will be used at a time. If you throw at a creature, your chance of hitting the creature is determined by your plusses to hit, your ability at throwing, and the object's plusses to hit. Once the creature is hit, the object may or may not do any actual damage to it. Certain objects in the dungeon can do great amounts of damage when thrown, but it's for you to figure out the obscure ones. Oil flasks are considered to be lit before thrown; therefore, they will do fire damage to a creature if they hit it. To use a bow with arrows, simply wield the bow and throw the arrows. Extra plusses to damage and hitting are gained by wielding the proper weapon and throwing the corresponding ammo. A heavy crossbow with bolts for example, is a killer... i - Display a list of objects being carried. This command displays a list of all objects being carried, but not currently in use. You may carry up to 22 different kinds of objects, not including those in your equipment list. Depending upon your strength, you will be able carry many identical objects before hitting your weight limit. j - Jam a door with an iron spike. {S - spike} Most humanoid and many intelligent creatures can simply open a closed door, and can eventually get through a locked door. Therefore you may spike a door in order to jam it. Each spike used on a door will increase its strength, although the more spikes you add, the less effect each additional spike has. It is very easy to jam a door so much as to make it impossible for your character to bash it down, so spike doors wisely. The bigger a creature is, the easier it can bash a door down. Therefore twenty or more spikes might be necessary to slow down a dragon, where one spike would slow down a kobold. This command can be counted. l - Look in a direction. {x - examine} The Look command is useful in identifying the exact type of The Dungeons of Moria Page 20 object or creature shown on the screen. Also, if a creature is on top of an object, the look command will describe both. You can see creatures and objects up to 200 feet away (20 spaces). You may freely use the Look command without the creatures getting a move on you. Looking in a particular direction sees everything within a cone of vision which just overlaps the cones of the two adjacent directions. Looking with the null direction `5' (or `.') sees everything which there is to be seen. You are also able to access you monster memories with this command. If you see a creature, you are prompted to ask if you wish to see a short paragraph of information about your experiences with that creature. See also the section on being attacked. m - Cast a magic spell. To cast a spell, a character must have previously learned it, and must also have in the inventory a magical book from which the spell may be read. Each spell has a chance of failure which starts out fairly large but decreases as a character gains levels. If a character does not have enough mana, the chance of failure is greatly increased, and he gambles on losing a point of constitution. You will be prompted for confirmation before trying to cast a spell when you don't have enough mana. Since a character must read the spell from a book, he cannot be blind or confused when cast- ing a spell, and there must be some light present. o - Open a door, chest, or lock. To open an object such as a door or chest, you must use the Open command. If the object is locked, the Open command will attempt to pick the lock, based on your ability at disarming. If an object is trapped and you open it, the trap will be set off. This command can be counted, because you may need several tries to get a locked door or chest open. p - Read a prayer. To pay effectively, a character must have learned the prayer, and must also have in the inventory a holy book from which the prayer may be read. Each prayer has a chance of being ignored which starts out fairly large but decreases as a character gains levels. If a character does not have enough mana, the chance of failure is greatly increased, and he gambles on losing a point of constitution. You will be prompted for confirmation before trying to pray when you don't have enough mana. Since a character must read the prayer from a book, he cannot be blind or confused when praying, and there must be some light present. q - Quaff a potion. To drink a potion use the Quaff command. A potion affects The Dungeons of Moria Page 21 the player in some manner. The effects of the potion may be immediately noticed, or they may be subtle and unnoticed. r - Read a scroll. To read a scroll use the Read command. Most scroll spells either affect the player or the area around the player; a few cases such as identify scrolls act on other objects. Two scrolls, the identify scroll and the recharge scroll, have titles which can be read without setting them off, and by pressing ESCAPE can be saved for future use. s - Search general area one turn. The Search command can be used to locate hidden traps and secret doors about the player. More than a single turn of searching will be required in most cases. You should always search a chest before trying to open it because they are generally trapped. This command can be counted, which is useful if you are really sure of finding something eventu- ally. A counted search ends as soon as anything is found. t - Take off a piece of equipment. {T} Use the Take Off command to remove an object from use, and return it to your inventory. Occasionally you will run into a cursed item which cannot be removed. Cursed items are always bad, and can only be taken off after removing the curse. u - Use a staff. {Z - Zap} The Use command will activate a staff. Like scrolls, most staffs have an area effect. Because staffs are generally more powerful than most other items, they are also harder to use correctly. v - Display current version of game. The Version command displays the credits for the current version of moria. w - Wear or wield an item being carried. To wear or wield an object in your inventory, use the Wear/Wield command. If another object is already in use for the same function, it is automatically removed first; if you are wearing two rings, you are given a choice of which one to remove. An object's bonuses cannot be gained until it is worn or wielded. x - Exchange primary and secondary weapons. {X} A secondary weapon is any weapon which may be needed often. Instead of searching through your inventory, you may use the exchange command to keep the weapon ready. For instance, if you wanted to use your bow most of the time, but needed a sword for close combat, you could wield your sword, use the exchange command to make it the secondary weapon, then wield your bow. If the sword was suddenly needed, simply use the exchange command to switch between the bow and the sword. The Dungeons of Moria Page 22 / - Identify a character shown on screen. Use the identify command to find out what a character displayed on the screen stands for. For instance, by press- ing `/.', you can find out that the `.' stands for a floor spot. When used with a creature, the identify command will tell you only what class of creature the symbol stands for, not the specific creature; therefore, use the look command for this information. If you identify the character for a creature in your monster memory, you are also prompted to ask if you wish to see a paragraph of information on those creatures identified by the given character. Several creatures may be identified in this way. Typing ESCAPE after the paragraph for any creature will abort back to command level. See also the section on being attacked. ? - Display a list of commands. The ? command displays a quick reference help page on the screen. - - Move without pickup. This is followed by a move command, and causes you to move over any object without picking it up. You can associate a count with this command. = - Set options. This is a free move, to set various moria options. The available options are: (1) Cut known corners when running. This is on by default, and the only reason for switching it off would be if you had the search flag on and wished to look for doors in the extremity of every corner. (2) Examine potential corners when running. This is on by default, and allows you to run along an unknown curving cor- ridor. If, however, you are running from a creature, you may wish to switch this option off, because the creature will cut the corner. (3) Print self during a run. This is off by default, which gives faster screen updating. (4) Stop when map sector changes. This is off by default, but can be switched on if you wish to stop running whenever a new part of the dungeon appears in view. (5) Treat open doors as empty space while running. This is off by default, in which case you stop whenever you run up to an open door. (6) Prompt to pick up objects. This is off by default, in which case stepping over an object automatically causes you to The Dungeons of Moria Page 23 pick it up. With the option on, you get prompted in all such cases with a description of the object to see if you really want to take it. (7) Rogue like command set. This option controls the command set in use. It is off by default. (8) Show weights in inventory. This is off by default: switch- ing it on causes the inventory and equipment listings to include the weight of all objects. This may be useful to know if your pack is getting too heavy. (9) Highlight and notice mineral seams. This is off by default. Switching it on causes quartz and magma to be displayed as `%' instead of `#'; also, it causes the look command to treat them as interesting objects. This is handy when min- ing. Setting this option does not immediately highlight all minerals, but only those which are subsequently displayed. To display all minerals, just move the map around a bit with the `Where' (or `Locate') command. (10)Beep for invalid character. This is on by default. When on, the program will beep for most invalid characters, such as trying to choose a spell that you haven't learned yet. When off, there are no such beeps. (11)Display rest/repeat counts. This is on by default. When on, the program will progressively display the remaining turns left while resting, and for repeated commands. For those trying to play over a 2400 bps or less connection, or for those playing on very slow microcomputers, turning this off will make resting and repeated commands work much fas- ter. The setting of all these options persist in your savefile, even after you die. ^P - Previous message. The Control-P command will redisplay the last message printed on the message line at the top of your screen. A second such command will display all of the saved messages. You may also give this command a count to specify the number of previous messages to display. At present, only 22 mes- sages are saved. ^K - Quit the game without saving. {Q} To exit the game without saving your character (i.e. kill him/her) use the Control-K command. Once exited in this manner, your character is nonrecoverable. ^X - Save your character and exit the game. To save your game so that it can be restarted later, use the Control-X command. Save files will also be generated if the game crashes due to a system error. When you die, a reduced The Dungeons of Moria Page 24 save file is produced containing only your monster memory, and your option settings. { - Inscribe an object. This command can be used to inscribe any short string on an object. Inscriptions are limited to twelve characters. The inscription applies only to the particular object, it is not automatically transferred to all similar objects. Under certain circumstances, moria will itself inscribe objects: if they have been discovered to be cursed or enchanted, or if they have been sampled without being identified. In this last case, moria does in fact carefully inscribe every such item. If the inscription on an item is a single digit, that digit can be used to refer to it when using, wearing, or wielding an item from your pack. For example, if you keep a pick in your pack with the inscription 1, you can switch to the pick by wielding item 1 without checking your full inventory list to find out which item the pick is. ! - Shell out of game. Use the Shell command `!' to temporarily exit the game to execute UNIX or MSDOS commands. You may reenter the game by typing exit to end the spawned process. This is not imple- mented in the Macintosh version. < - Go up an up staircase. If you move onto an up staircase you may use the `<' command to go up one level. There is always one staircase going up on every level except for the town level (this does not mean it's easy to find). Going up a staircase will always take you to a new dungeon area except for the town level, which remains the same for the duration of your character. > - Go down a down staircase. If you are on top of a down staircase you may use the `>' command to go down one level. There are always two or three staircases going down on each level, except the town level which has only one. Going down will always take you to a new dungeon area. . - Move in direction. {shift} The Run command will move you in the indicated direction until either you have to make a choice as between two direc- tions, or something interesting happens. There are options which determine behavior at corners, and at screen boun- daries. More precisely, the conditions which stop a run are as follows: (1) A creature appears on the screen, one already on the screen moves, or a creature attacks you or casts a spell at you. (2) You move next to an object, or a feature such as a door or The Dungeons of Moria Page 25 trap. (3) You come to the end of open space, or the end of a passage, or a junction of passages, or a hole in a wall. (4) Anything typed during a run causes the run to stop. The character causing this to occur is ignored. It is best to use a space, which is ignored as a command, just in case the run stops just before you type the character. (5) Various changes of state, such as recovery from fear or loss of heroism, will stop a run. Corners are more complex. A corner allows a choice between adjacent rectangular and diagonal directions. If you can see walls which ensure that the diagonal gives a faster traversal, then action is determined by the "cut corners" options. If it is set, then you move diagonally through the corner. This gives you maximum speed (as is nice if you are fleeing a hidden creature). On the other hand, this option should not be set if you want more careful coverage (as when you are searching) so that you take two moves through the corner. At a potential corner, where walls are not yet visible ahead of the rectangular direction, the "examine corners" option is considered. If set, you will move straight into the corner, which will light up all the corner and so determine where you can go from there. This allows you to follow corners in new passages. If the option is not set, you stop. This allows highly cautious running where you want to stop at all potential choice points. If you move off the screen while running, then a new section of the dungeon is displayed and the run continues. However, if the "stop when map changes" option is set, you will stop. Again, this is an option for nervous players; after all, there may be a dragon on the new screen. 6. The Town Level The town level is where you will begin your adventure. The town consists of six buildings, each with an entrance, some townspeo- ple, and a wall which surrounds the town. The first time you are in town it will be daytime, but you may return to find that dark- ness has fallen. (Note that some spells may act differently in the town level.) 6.1. Townspeople The town contains many different kinds of people. There are the street urchins, young children who will mob an adventurer for money, and seem to come out of the woodwork when excited. The Dungeons of Moria Page 26 Blubbering Idiots are a constant annoyance, but not harmful. Public drunks wander about the town singing, and are of no threat to anyone. Sneaky rogues hang about watching for a likely victim to mug. And finally, what town would be complete without a swarm of half-drunk warriors, who take offense or become annoyed just for the fun of it. Most of the townspeople should be avoided by the largest possible distance when you wander from store to store. Fights will break out though, so be prepared. Since your character grew up in this world of intrigue, no experience is awarded for killing on the town level. 6.2. Supplies Your character will begin his adventure with some supplies already on him. Use the Inventory `i' command to check what these supplies are. It will be necessary to buy other supplies before continuing into the dungeon, however, so be sure to enter each of the stores. 6.3. Town Buildings You may enter any of the stores, if they are open, and barter with the owner for items you can afford. When bartering, you enter prices you will pay (or accept) for some object. You can either enter the absolute amount, or precede a number with a plus or minus sign to give a positive or negative increment on your previous offer. If you have previously given an increment or decrement amount, you can just type RETURN, and the program will use the last increment amount that you typed. But be warned that the owners can easily be insulted, and may even throw you out for a while if you insult them too often. To enter a store, simply move onto the entrance represented by the numbers 1 through 6. If you consistently bargain well in a store, that is, you reach the final offer much more often than not, then the store owner will eventually recognize that you are a superb haggler, and will go directly to the final offer instead of haggling with you. Items which cost less than 10 gold pieces do not count, as hag- gling well with these items is usually either very easy or almost impossible. Once inside a store, the store inventory will appear on the screen along with a set of options for your character. You may browse the store's inventory if it takes more than one page to display, and you may sell to, or purchase items from, his inven- tory. You can execute your inventory and equipment commands to see what you are carrying. Not shown with the options are the wear, take off, and exchange commands which will also work, but were excluded to keep the options simple. The Dungeons of Moria Page 27 Stores do not always have everything in stock. As the game progresses, they may get new items, so check from time to time. Also, if you sell them an item, it may get sold to a customer while you are adventuring, so don't always expect to be able to get back everything you have sold. Store owners will not buy harmful or useless items. If an object is unidentified, they will pay you some base price for it. Once they have bought it they will immediately identify the object. If it is a good object, they will add it to their inventory. If it was a bad bargain, they simply throw the item away. In any case, you may receive some knowledge of the item if another is encountered. The General Store The General Store sells foods, drinks, some clothing, torches, lamps, oil, shovels, picks, and spikes. All of these items, and some others, can be sold back to the Gen- eral store for money. The entrance to the General Store is a `1'. The Armory The Armory is where the town's armor is fashioned. All sorts of protective gear may be bought and sold here. The entrance to the Armory is a `2'. The Weaponsmith's Shop The Weaponsmith's Shop is where the town's weapons are fashioned. Hand and missile weapons may be purchased and sold here, along with arrows, bolts, and shots. The entrance to the Weaponsmith's is a `3'. The Temple The Temple deals in healing and restoration potions, as well as bless scrolls, word of recall scrolls, some approved pri- estly weapons, etc. The entrance to the Temple is a `4'. The Alchemy Shop The Alchemy Shop deals in all manner of potions and scrolls. The entrance to the Alchemy Shop is a `5'. The Magic User's Shop The Magic User's Shop is the most expensive of all the stores. It deals in all sorts of rings, wands, amulets, and staves. The entrance to the Magic Shop is a `6'. 7. Within The Dungeon Once your character is adequately supplied with food, light, armor, and weapons, he is ready to enter the dungeon. Move on top of the `>' symbol and use the down `>' command. Your charac- ter enters a maze of interconnecting staircases and finally passes through a one-way door. He is now on the first level of The Dungeons of Moria Page 28 the dungeon (50 feet), and must survive many horrible and chal- lenging encounters to find the treasure lying about. There are two sources for light once inside the dungeon: per- manent light which has been magically placed within rooms, and a light source carried by the player. If neither is present, the character will be unable to map or see any attackers. Lack of light will also affect searching, picking locks, and disarming. A character must wield a torch or lamp in order to supply his own light. Once a torch or lamp has only 50 or less turns left before burning out, the message "Your light is growing faint" will be displayed at random intervals. Once a torch is burnt out, it is useless and can be dropped. A lamp or lantern can be refilled with oil by using the Fill `F' command. You must of course be carrying extra oil to refill a lantern. 8. Attacking and Being Attacked Attacking is simple in moria. If you move into a creature, you attack it. You can attack from a distance by firing a missile, or by magical means such as aiming a wand. Creatures attack in the same way; if they move into you, they attack you. Some creatures can also cast spells from a distance, and others can breathe fire or worse on you from a distance. Creatures moving in walls can not be attacked by wands and other magic attacks normally stopped by walls. You can attack a creature in a wall normally though by trying to move into the wall space containing the creature. However, in order to attack an invisible creature in a wall, you must tunnel into the wall containing the creature. If you just try to move into the wall, you will bump your head and look quite silly. If you are wielding a weapon, the damage for the weapon is used when you hit a creature. Otherwise, you get two fist strikes. Very strong creatures can do a lot of damage with their fists... You may have a primary weapon, and a secondary weapon which is kept on your belt or shoulder for immediate use. You can switch between your primary and secondary weapons with the exchange com- mand. Be sure to wield the proper weapon when fighting. Hitting a dragon over the head with a bow will simply make him mad, and get you killed. Missile weapons, such as bows, can be wielded, and then the proper missile, in this case an arrow, can be fired across the room into a target. Missiles can be used without the proper mis- sile weapon, but used together they have a greater range and do far more damage. Hits and misses are determined by ability to hit versus armor class. A hit is a strike that does some damage; a miss may in fact reach a target, but fails to do any damage. Higher armor The Dungeons of Moria Page 29 classes make it harder to do damage, and so lead to more misses. 8.1. Monster Memories There are hundreds of different creatures in the mines of moria, many of which look the same on the screen. The exact species of a creature can be discovered by looking at it. It is also very difficult to keep track of the capabilities of various creatures. Rather than forcing you to keep notes, moria automatically keeps track of your experiences with a particular creature. This is called the monster memory. You monster memory recalls the par- ticular attacks of each creature which you have suffered, as well as recalling if you have observed them to multiply or move errat- ically, or drop treasure, or many other attributes. If you have killed enough of a particular creature, or suffered enough attacks, recalling the monster memory may also provide you with information not otherwise available, such as a armor class or hit dice. These are not explained, but may be useful to give the relative danger of each creature. This memory can be passed on to a new character even after you die, by means of a reduced save file. 8.2. Your Weapon Carrying a weapon in your backpack does you no good. You must wield a weapon before it can be used in a fight. A secondary weapon can be kept by wielding it and then using the exchange command. A secondary weapon is not in use, simply ready to be switched with the current weapon if needed. Weapons have two main characteristics, their ability to hit and their ability to do damage, expressed as `(+#,+#)'. A normal weapon would be `(+0,+0)'. Many weapons in moria have magical bonuses to hit and/or do damage. Some weapons are cursed, and have penalties that hurt the player. Cursed weapons cannot be unwielded until the curse is lifted. Moria assumes that your youth in the rough environment near the dungeons has taught you the relative merits of different weapons, and displays as part of their description the damage dice which define their capabilities. The ability to damage is added to the dice roll for that weapon. The dice used for a given weapon is displayed as `#d#'. The first number indicates how many dice to roll, and the second indicates how many sides they have. A "2d6" weapon will give damage from 2 to 12, plus any damage bonus. The weight of a weapon is also a consideration. Heavy weapons may hit harder, but they are also harder to use. Depending on your strength and the weight of the weapon, you may get several hits in one turn. Missile booster weapons, such as bows, have their characteristics The Dungeons of Moria Page 30 added to those of the missile used, if the proper weapon/missile combination is used. Also, these weapons will multiply the base damage of the missile by a number from 2 to 4, depending on the strength of the weapon. This multiplier is displayed as `(x#)'. Although you receive any magical bonuses an unidentified weapon may possess when you wield it, those bonuses will not be added in to the displayed values of to-hit and to-dam on your character sheet. You must identify the weapon before the displayed values reflect the real values used. Finally, some rare weapons have special abilities. These are called ego weapons, and are feared by great and meek. An ego sword must be wielded to receive benefit of its abilities. Special weapons are denoted by the following abbreviations: DF - Defender. A magical weapon that helps the wielder defend himself, thus increasing his/her armor class, and protecting him/her against damage from fire, frost, acid, lightning, and falls. This weapon also will increase your stealth, let you see invisible creatures, protect you from paralyzation attacks, and help you regenerate hit points and mana faster. As a result of the regeneration ability, you will use up food faster than normal while wielding such a weapon. FB - Frost Brand. A magical weapon of ice that delivers a cold critical to heat based creatures. It will inflict one and a half times the normal damage when used against a heat based creature. FT - Flame Tongue. A magical weapon of flame that delivers a heat critical to cold based creatures. It will inflict one and a half times the normal damage when used against cold based or inflamm- able creatures. HA - Holy Avenger. A Holy Avenger is one of the most powerful of weapons. A Holy Avenger will increase your strength and your armor class. This weapon will do extra damage when used against evil and undead creatures, and will also give you the abil- ity to see invisible creatures. SA - Slay Animal. A Slay Animal weapon is a special purpose weapon whose sole intent is to destroy all the dangerous animals in the world. An animal is any creature natural to the world. Therefore an orc would not be an animal, but a giant snake would be. This will inflict twice the normal amount of damage when used against an animal. SD - Slay Dragon. The Dungeons of Moria Page 31 A Slay Dragon weapon is a special purpose weapon whose sole intent is to destroy dragon-kind. Therefore, when used against a dragon, the amount of damage done is four times the normal amount. SE - Slay Evil. A Slay Evil weapon is a special purpose weapon whose sole intent is to destroy all forms of evil. When used against an evil creature, either alive or undead, the damage done twice the normal amount. SU - Slay Undead. A Slay Undead weapon is a special purpose weapon whose sole intent is to destroy all forms of undead. This weapon is hated and feared by the intelligent undead, for a single blow from this weapon will inflict three times the normal amount of damage. This weapon also gives you the ability to see invisible creatures, which is especially useful against undead, since many of them are normally invisible. 8.3. Body and Shield Bashes Weight is the primary factor in being able to bash something, but strength plays a role too. After bashing, a character may be off balance for several rounds depending upon his dexterity. Doors can be broken down by bashing them. Once a door is bashed open, it is forever useless and cannot be closed. Chests too may be bashed open, but be warned that the careless smashing of a chest often ruins the contents. Bashing open a chest will not disarm any traps it may contain, but does allow the strong and ignorant to see what is inside. Finally, a creature may be bashed. If a shield is currently being worn, the bash is a shield bash and will do more damage. In either case, a bash may throw an opponent off balance for a number of rounds, allowing a player to get in a free hit or more. If the player is thrown off balance, his opponent may get free hits on him. This is a risky attack. 8.4. Your Armor Class Armor class is a number that describes the amount and the quality of armor being worn. Armor class will generally run from about 0 to 60, but could become negative or greater than 60 in rare cases. The larger your armor class, the more protective it is. A nega- tive armor class would actually help get you hit. Armor protects you in three manners. One, it makes you harder to be hit for damage. A hit for no damage is the same as a miss. Two, good The Dungeons of Moria Page 32 armor will absorb some of the damage that your character would have taken. An armor class of 30 would absorb 15% of any damage meant for him. Three, acid damage is reduced by wearing body armor. It is obvious that a high armor class is a must for sur- viving the lower levels of moria. Each piece of armor has an armor class adjustment, and a magical bonus. Armor bought in town will have these values displayed with its description. Armor that is found within the dungeon must be identified before these values will be displayed. All armor always has the base armor class displayed, to which the bonus is added. It is always possible to figure this out anyway, by watching the effect it has on your displayed armor class. Armor class values are always displayed between a set of brackets as `[#]' or `[#,+#]'. The first value is the armor class of the item. The second number is the magical bonus of the item which is only displayed if known, and will always have a sign preceding the value. There are a few cases where the form `[+#]' is used, meaning the object has no armor class, only a magical armor bonus if worn. Body armor may also have a (-#) displayed in parentheses; this is a penalty to hit, because the bulk of the armor makes it more difficult to swing a weapon freely. Some pieces of armor will possess special abilities denoted by the following abbreviations: RA - Resist Acid. A character using such an object will take only one-third normal damage from any acid thrown upon him. In addition, armor so enchanted will resist the acid's effects and not be damaged by it. RC - Resist Cold. A character using a resist cold object will take only one- third damage from frost and cold. RF - Resist Fire. A character using a resist fire object will take only one- third damage from heat and fire. RL - Resist Lightning. A character using a resist lightning object will take only one-third damage from electrical attacks. R - Resistance. A character wearing armor with this ability will have resis- tance to Acid, Cold, Fire, and Lightning as explained in each part above. 8.5. Crowns Some crowns also have special magical abilities that improve your The Dungeons of Moria Page 33 chances in a battle. Crown of Might This is the great crown of the warriors. The wearer will have an increased strength, dexterity, and constitution, and will also be immune to any foe's attempt to slow or paralyze him or her. Crown of the Magi This is the great crown of the wizards. The wearer will have an increased intelligence, and will also be given resistance against fire, frost, acid, and lightning. Crown of Lordliness This is the great crown of the priests. The wearer will have an increased wisdom and charisma. Crown of Seeing This is the great crown of the rogues. The wearer will be able to see even invisible creatures, and will have an increased ability to locate traps and secret doors. Crown of Regeneration This crown will help you regenerate hit points and mana more quickly than normal, allowing you to fight longer before needing to rest. You will use of food faster than normal while wearing this crown because of the regenerative effects. Crown of Beauty This crown looks impressive, and will increase your charisma, but is otherwise not useful. 9. Objects Found In The Dungeon The mines are full of objects just waiting to be picked up and used. How did they get there? Well, the main source for useful items are all the foolish adventurers that proceeded into the dungeon before you. They get killed, and the helpful creatures scatter the various treasure throughout the dungeon. Most cursed items are placed there by the joyful evil sorcerers, who enjoy a good joke when it gets you killed. You pick up objects by moving on top of them. You can carry up to 22 different items in your backpack while wearing and wielding many others. Although you are limited to 22 different items, you may be carrying several items of each kind, restricted only by the amount of weight your character can carry. Your weight limit is determined by your strength. Only one object may occupy a given floor location, which may or may not also contain one creature. Doors, traps, and staircases are considered objects for this purpose. The Dungeons of Moria Page 34 If you try to carry more weight than your limit, you will move more slowly than normal until you drop the extra weight. If picking up an object would take you over your weight limit, then you will be asked whether you really want to pick it up. It is a good idea to leave the object alone if you are fleeing from a monster. Many objects found within the dungeon have special commands for their use. Wands must be Aimed, staffs must be Used, scrolls must be Read, and potions must be Quaffed. In any case, you must first be able to carry an object before you can use it. Some objects, such as chests, are very complex. Chests contain other objects and may be trapped, and/or locked. Read the list of player commands carefully for a further understanding of chests. One item in particular will be discussed here. The scroll of "Word-of-Recall" can be found within the dungeon, or bought at the temple in town. It acts in two manners, depending upon your current location. If read within the dungeon, it will teleport you back to town. If read in town, it will teleport you back down to the deepest level of the dungeon on which your character has previously been. This makes the scroll very useful for get- ting back to the deeper levels of moria. Once the scroll has been read, it takes a while for the spell to act, so don't expect it to save you in a crisis. The game provides some automatic inscriptions to help you keep track of your possessions. Wands and staves which are known to be empty will be inscribed with "empty". Objects which have been tried at least once, but haven't been identified yet will be inscribed with "tried". Cursed objects are inscribed with "damned". Also, occasionally you will notice that something in your inventory or equipment list seems to be magical. High level characters are much more likely to notice this than beginning characters. When you do notice this, the item in question will be inscribed with "magik". And lastly, a final warning: not all objects are what they seem. Skeletons lying peacefully about the dungeon have been known to get up... 9.1. Cursed Objects Some objects, mainly armor and weapons, have had curses laid upon them. These horrible objects will look like any other normal item, but will detract from your character's stats or abilities if worn. They will also be impossible to remove until a remove curse is done. If you wear or wield a cursed item, you will immediately feel something wrong. The item will also be inscribed "damned". The Dungeons of Moria Page 35 9.2. Mining Much of the treasure within the dungeon can be found only by min- ing it out of the walls. Many rich strikes exist within each level, but must be found and mined. Quartz veins are the richest, yielding the most metals and gems, but magma veins will have some hordes hidden within. Mining is virtually impossible without a pick or shovel. Picks and shovels have an additional magical ability expressed as `(+#)'. The higher the number, the better the magical digging ability of the tool. A pick or shovel also has plusses to hit and damage, and can be used as a weapon. When a vein of quartz or magma is located, the character should wield his pick or shovel and begin digging out a section. When that section is removed, he should locate another section of the vein, and begin the process again. Since granite rock is much harder to dig through, it is much faster to follow the vein exactly and dig around the granite. There is an option for highlighting magma and quartz. If the character has a scroll or staff of treasure location, he can immediately locate all strikes of treasure within a vein shown on the screen. This makes mining much easier and more pro- fitable. It is sometimes possible to get a character trapped within the dungeon by using various magical spells and items. So it is a very good idea to always carry some kind of digging tool, even when you are not planning on tunneling for treasure. 9.3. Staircases, Secret Doors, Passages, and Rooms Staircases are the manner in which you get deeper, or climb out of the dungeon. The symbols for the up and down staircases are the same as the commands to use them. A `<' represents an up staircase and a `>' represents a down staircase. You must move your character over the staircase before you can use them. Each level has at least one up staircase, and at least two down staircases. There are no exceptions to this rule. You may have trouble finding some well hidden secret doors, but the stairs are there. Many secret doors are used within the dungeon to confuse and demoralize adventurers foolish enough to enter. But with some luck, and lots of concentration, you can find these secret doors. Secret doors will sometimes hide rooms or corridors, or even entire sections of that level of the dungeon. Sometimes they simply hide small empty closets or even dead ends. Creatures in the dungeon will generally know and use these secret The Dungeons of Moria Page 36 doors. If they leave one open, you will be able to go right through it. If they close it behind them you will have to search for the catch first. Once a secret door has been discovered by you, it is drawn as a known door and no more searching will be required to use it. 10. Winning The Game Once your character has progressed into killing dragons with but a mean glance and snap of his fingers, he may be ready to take on the Balrog. The Balrog will appear on most levels after level 49, so don't go down there until you are ready for him. The Balrog cannot be killed in some of the easier methods used on normal creatures. Because of the Balrog's cunning, he will teleport away to another level if a spell such as destruction is used upon him, and the Balrog cannot be polymorphed, slept, con- fused, or genocided. Magical spells like coldball are effective against him, as are weapons, but he is difficult to kill, and if allowed to escape to another level can heal himself. If you should actually survive the attempt of killing the Balrog, you will receive the status of WINNER. Since you have defeated the toughest creature alive, your character is ready to retire and cannot be saved. When you quit the game, your character receives a surprise bonus score. 11. Upon Death and Dying If your character falls below 0 hit points, he has died and can- not be restored. A tombstone showing information about your character will be displayed. You are also permitted to get a record of your character, and all your equipment (identified) either on the screen or in a file. Your character will leave behind a reduced save file, which con- tains only the monster memory and your option choices. It may be restored, in which case the new character is generated exactly as if the file was not there, but the new player will find his mon- ster memory containing all the experience of past incarnations. 12. Wizards There are rumors of moria Wizards which, if asked nicely, can explain details of the moria game that seem complicated to beginners. moria-5.6.debian.1/doc/spells.doc0000644000175000017500000002641005613574142014733 0ustar pjbpjbAddendum to the manual for Moria. Proposed contribution written by Mike Marcelais North Carolina School of Science And Math mrm@odin.ncssm.edu games@odin.ncssm.edu 1. Magic Spells All player characters except Warriors are able to learn some form of magic spells. There are two kinds of magic, Magic spells, which Mages, Rogues, and Rangers get, and prayers, which Priests and Paladins have. Each spell has a minimum level required for learning it, a mana score, which is the mana points required to cast it, and a failure percentage. Mana points are determined by your experience level, and the level of your key stat. For Mages, Rogues, and Rangers, the key stat is intelligence, for Priests and Paladins the key stat is wisdom. The effect of your key stat is shown by the following table. Stat Level Factor 3-7 0 8-17 1 18-18/49 3/2 18/50-18/69 2 18/70-18/89 5/2 18/90-18/99 3 18/100 4 Your Mana score is the Factor times your experience level plus 1. If your key stat is 7 or less, your Mana score will be zero (not one) and you will not be able to use any spells. If you attempt to cast a spell that calls for more Mana than you have, the rate of failure is much greater than normal, you will faint for a few turns afterward, and you stand the chance of damaging your health. 1.1 Priest Spells Priest spells are received from the character's deity. When the 'G' command is issued to learn new spells, spells are chosen randomly from the spells that you are able to cast. You need not have the book the spell is in to learn it, because your God gave it to you, but you do need the book to cast the spell. Failure percentages and spell effectiveness are based on Wisdom for priests and paladins. 1.1.1 Priest spell levels and Mana This is a table of all the spells, with the mana and level of achievement for Priests and Paladins. Priest Paladin (Beginner's Handbook) Lv Mana Lv Mana A Detect Evil 1 1 1 1 B Cure Light Wounds 1 2 2 2 C Bless 1 2 3 3 D Remove Fear 1 2 5 3 E Call Light 3 2 5 4 F Find Traps 3 3 7 5 G Detect Doors/Stairs 3 3 7 5 H Slow Poison 3 3 9 7 (Words of Wisdom) A Blind Creature 5 4 9 7 B Portal 5 4 9 8 C Cure Medium Wounds 5 4 11 9 D Chant 5 5 11 10 E Sanctuary 7 5 11 10 F Create Food 7 5 13 10 G Remove Curse 7 6 13 11 H Resist Heat and Cold 7 7 15 13 (Chants and Blessings) A Neutralize Poison 9 6 15 15 B Orb of Draining 9 7 17 15 C Cure Serious Wounds 9 7 17 15 D Sense Invisible 11 8 19 15 E Protection from Evil 11 8 19 15 F Earthquake 11 9 21 17 G Sense Surroundings 13 10 23 17 H Cure Critical Wounds 13 11 25 20 I Turn Undead 15 12 27 21 (Exorcisms and Dispellings) A Prayer 15 14 29 22 B Dispel Undead 17 14 31 24 C Heal 21 16 33 28 D Dispel Evil 25 20 35 32 E Glyph of Warding 33 24 37 36 F Holy Word 39 32 39 38 1.1.2 Priest Spell Descriptions This is a short description of each of the spells, listed alphabetically. Bless - Improves armor class and fighting ability for a short period of time. Blind Creature - Blinds a creature for a short period of time. Call Light - Lights up an area. Chant - Improves armor class and fighting ability for a medium period of time. Create Food - Causes a food item to be dropped at your feet. Cure Critical Wounds - Cures a very large number of hit points. Cure Light Wounds - Cures a small number of hit points. Cure Medium Wounds - Cures a medium number of hit points. Cure Serious Wounds - Cures a large number of hit points. Detect Doors/Stairs - Finds all the doors and stairs on the screen. Detect Evil - Finds all the evil creatures on the screen. Dispel Evil - Attempts to destroy the evil creature. Dispel Undead - Attempts to destroy the undead creature. Earthquake - Randomly toggles corridors into walls and vice versa. Find Traps - Locates all the traps on the screen. Glyph of Warding - Leaves a 'Glyph' that monsters won't pass over. Heal - Restores 200 Hit Points. Holy Word - Dispels evil, removes fear, cures poison, restores 1000 HPs, restores all stats, and invulnerability for 3 turns. Neutralize Poison - Cures you of poison. Orb of Draining - Offensive spell that drains levels from monsters. Portal - Teleports you a short distance away. Prayer - Improves armor class and fighting ability for a long period of time. Protection from Evil - Causes evil creatures to do less damage to you. Remove Curse - Removes {damned} objects that you are welding. Remove Fear - Negates the fear placed on you by an enemy. Resist Heat and Cold - Reduce damage you suffer from heat or cold attacks. Sanctuary - Causes neighboring monsters to fall asleep for a while. Sense Invisible - Finds all invisible creatures on the screen. Sense Surroundings - Maps the dungeon appearing on the screen. Slow Poison - Reduces the rate HP are lost due to poison. Turn Undead - Attempts to cause undead creatures to flee. 1.2 Mage Spells Mage Spells are more powerful and offensive in nature than Priest spells. This offsets the fact that magicians are generally weaker than any other class. Because mage spells are learned though study, you must have the correct Magic book to learn and cast a spell. Learning spells can be banked up. For example: You are a second level Mage who had learned Magic Missile and can learn one more spell. You do not wish to learn Detect Monsters, Phase Door or Light Area. You can wait until you are third level and learn both the Cure Light Wounds and Stinking Cloud, both third level spells. Spell failure and effectiveness is based on intelligence for Mages, Rangers, and Rogues. Rangers can learn all but the most powerful offensive spell. Rogues can not learn any offensive spell. 1.2.1 Mage Spell levels and Mana Mage Ranger Rogue (Beginners-Magik) Lv Mana Lv Mana Lv Mana A Magic Missile 1 1 3 1 -- -- B Detect Monsters 1 1 3 2 5 1 C Phase Door 1 2 3 2 7 2 D Light Area 1 2 5 3 9 3 E Cure Light Wounds 3 3 5 3 11 4 F Find Hidden Traps/Doors 3 3 5 4 13 5 G Stinking Cloud 3 3 7 5 -- -- (Magik I) A Confusion 3 4 7 6 15 6 B Lightning Bolt 5 4 9 7 -- -- C Trap/Door Destruction 5 5 9 8 17 7 D Sleep I 5 5 11 8 19 8 E Cure Poison 5 5 11 9 21 9 F Teleport Self 7 6 13 10 -- -- G Remove Curse 7 6 13 11 23 10 H Frost Bolt 7 6 15 12 -- -- I Turn Stone to Mud 9 7 15 13 -- -- (Magik II) A Create Food 9 7 17 17 25 12 B Recharge Item I 9 7 17 17 27 15 C Sleep II 9 7 21 17 -- -- D Polymorph Other 11 7 21 19 -- -- E Identify 11 7 23 25 29 18 F Sleep III 13 7 23 20 -- -- G Fire Bolt 15 9 25 20 -- -- H Slow Monster 17 9 25 21 -- -- (Mages Guide to Power) A Frost Ball 19 12 27 21 -- -- B Recharge Item II 21 12 29 23 -- -- C Teleport Other 23 12 31 25 -- -- D Haste Self 25 12 33 25 -- -- E Fire Ball 29 18 35 25 -- -- F Word of Destruction 33 21 37 30 -- -- G Genocide 37 25 -- -- -- -- Note: Rangers don't get spells until 3'rd level, Rogues 5'th level. 1.2.2 Mage Spell Descriptions Confusion - Confuses a monster for a short time. Create Food - Causes a food item to be dropped at your feet. Cure Light Wounds - Restores a small number of hit points. Cure Poison - Neutralizes the poison running through your veins. Detect Monsters - Displays all the monsters on the screen. Find Hidden Traps/Doors - Locates all the secret traps and doors. Fire Ball - Shoots a ball of flame toward a monster. Fire Bolt - Shoots a bolt of flame toward a monster. Frost Ball - Shoots a ball of frost toward a monster. Frost Bolt - Shoots a bolt of frost toward a monster. Genocide - Destroys a particular monster on the level. Haste Self - Causes you to move faster temporarily. Identify - Identifies an unknown object in your pack. Light Area - Illuminates the area you are in with light. Lightning Bolt - Shoots a bolt of lightning at your enemy. Magic Missile - Traditional bolt of magic used to damage enemies. Phase Door - Teleports you a short distance. Polymorph Other - Polymorphs a monster into a different creature. Recharge Item I and II - Recharges a staff, rod, or wand. Remove Curse - Allows you to unwield {damned} items. Sleep I - Causes a monster of your choosing to fall asleep. Sleep II - Causes neighboring monsters to fall asleep. Sleep III - Causes all monsters in range to fall asleep. Slow Monster - Causes a monster to move slower. Stinking Cloud - Shoots a ball of noxious vapors to do damage. Teleport Self - Teleports you to a new place on the level. Teleport Other - Teleports an enemy to a new place on the level. Trap/Door Destruction - Destroys all neighboring doors and traps. Turn Stone to Mud - Causes a wall (or other stone object) to melt. Word of Destruction - Destroys the entire screen. For spells that come in numbered versions (Sleep I, II, III, etc), the higher numbers have a higher effectiveness, but greater change of spell failure and greater Mana cost. 1.3 Using Offensive Spells Against Monsters Monsters have a chance to save themselves from damage caused by offensive spells, just like the player has a chanced to be saved from damage by monster spells. This chance is greater for higher level monsters than for lower level monsters. Also, some spells will never work against monsters whose level is higher than the character's experience level. Many monsters are immune to certain kinds of attack, and will suffer little or no damage from such attacks. For example, a fire breathing dragon will suffer little damage from a fire ball, but will suffer greatly from a frost ball. Also, Undead creatures will not be affected by sleep spells, since they never sleep. moria-5.6.debian.1/doc/moria2.ms0000644000175000017500000006411205613574145014500 0ustar pjbpjb.NH 1 The Town Level .LP The town level is where you will begin your adventure. The town consists of six buildings, each with an entrance, some townspeople, and a wall which surrounds the town. The first time you are in town it will be daytime, but you may return to find that darkness has fallen. (Note that some spells may act differently in the town level.) .NH 2 Townspeople .LP The town contains many different kinds of people. There are the street urchins, young children who will mob an adventurer for money, and seem to come out of the woodwork when excited. Blubbering Idiots are a constant annoyance, but not harmful. Public drunks wander about the town singing, and are of no threat to anyone. Sneaky rogues hang about watching for a likely victim to mug. And finally, what town would be complete without a swarm of half-drunk warriors, who take offense or become annoyed just for the fun of it. .LP Most of the townspeople should be avoided by the largest possible distance when you wander from store to store. Fights will break out though, so be prepared. Since your character grew up in this world of intrigue, no experience is awarded for killing on the town level. .NH 2 Supplies .LP Your character will begin his adventure with some supplies already on him. Use the Inventory `i' command to check what these supplies are. It will be necessary to buy other supplies before continuing into the dungeon, however, so be sure to enter each of the stores. .NH 2 Town Buildings .LP You may enter any of the stores, if they are open, and barter with the owner for items you can afford. When bartering, you enter prices you will pay (or accept) for some object. You can either enter the absolute amount, or precede a number with a plus or minus sign to give a positive or negative increment on your previous offer. If you have previously given an increment or decrement amount, you can just type RETURN, and the program will use the last increment amount that you typed. But be warned that the owners can easily be insulted, and may even throw you out for a while if you insult them too often. To enter a store, simply move onto the entrance represented by the numbers 1 through 6. .LP If you consistently bargain well in a store, that is, you reach the final offer much more often than not, then the store owner will eventually recognize that you are a superb haggler, and will go directly to the final offer instead of haggling with you. Items which cost less than 10 gold pieces do not count, as haggling well with these items is usually either very easy or almost impossible. .LP Once inside a store, the store inventory will appear on the screen along with a set of options for your character. You may browse the store's inventory if it takes more than one page to display, and you may sell to, or purchase items from, his inventory. You can execute your inventory and equipment commands to see what you are carrying. Not shown with the options are the wear, take off, and exchange commands which will also work, but were excluded to keep the options simple. .LP Stores do not always have everything in stock. As the game progresses, they may get new items, so check from time to time. Also, if you sell them an item, it may get sold to a customer while you are adventuring, so don't always expect to be able to get back everything you have sold. .LP Store owners will not buy harmful or useless items. If an object is unidentified, they will pay you some base price for it. Once they have bought it they will immediately identify the object. If it is a good object, they will add it to their inventory. If it was a bad bargain, they simply throw the item away. In any case, you may receive some knowledge of the item if another is encountered. .IP "The General Store" The General Store sells foods, drinks, some clothing, torches, lamps, oil, shovels, picks, and spikes. All of these items, and some others, can be sold back to the General store for money. The entrance to the General Store is a `1'. .IP "The Armory" The Armory is where the town's armor is fashioned. All sorts of protective gear may be bought and sold here. The entrance to the Armory is a `2'. .IP "The Weaponsmith\'s Shop" The Weaponsmith's Shop is where the town's weapons are fashioned. Hand and missile weapons may be purchased and sold here, along with arrows, bolts, and shots. The entrance to the Weaponsmith's is a `3'. .IP "The Temple" The Temple deals in healing and restoration potions, as well as bless scrolls, word of recall scrolls, some approved priestly weapons, etc. The entrance to the Temple is a `4'. .IP "The Alchemy Shop" The Alchemy Shop deals in all manner of potions and scrolls. The entrance to the Alchemy Shop is a `5'. .IP "The Magic User\'s Shop" The Magic User's Shop is the most expensive of all the stores. It deals in all sorts of rings, wands, amulets, and staves. The entrance to the Magic Shop is a `6'. .NH 1 Within The Dungeon .LP Once your character is adequately supplied with food, light, armor, and weapons, he is ready to enter the dungeon. Move on top of the `>' symbol and use the down `>' command. Your character enters a maze of interconnecting staircases and finally passes through a one-way door. He is now on the first level of the dungeon (50 feet), and must survive many horrible and challenging encounters to find the treasure lying about. .LP There are two sources for light once inside the dungeon: permanent light which has been magically placed within rooms, and a light source carried by the player. If neither is present, the character will be unable to map or see any attackers. Lack of light will also affect searching, picking locks, and disarming. .LP A character must wield a torch or lamp in order to supply his own light. Once a torch or lamp has only 50 or less turns left before burning out, the message \*QYour light is growing faint\*U will be displayed at random intervals. Once a torch is burnt out, it is useless and can be dropped. A lamp or lantern can be refilled with oil by using the Fill `F' command. You must of course be carrying extra oil to refill a lantern. .NH 1 Attacking and Being Attacked .LP Attacking is simple in \fImoria\fP. If you move into a creature, you attack it. You can attack from a distance by firing a missile, or by magical means such as aiming a wand. Creatures attack in the same way; if they move into you, they attack you. Some creatures can also cast spells from a distance, and others can breathe fire or worse on you from a distance. .LP Creatures moving in walls can not be attacked by wands and other magic attacks normally stopped by walls. You can attack a creature in a wall normally though by trying to move into the wall space containing the creature. However, in order to attack an invisible creature in a wall, you must tunnel into the wall containing the creature. If you just try to move into the wall, you will bump your head and look quite silly. .LP If you are wielding a weapon, the damage for the weapon is used when you hit a creature. Otherwise, you get two fist strikes. Very strong creatures can do a lot of damage with their fists... You may have a primary weapon, and a secondary weapon which is kept on your belt or shoulder for immediate use. You can switch between your primary and secondary weapons with the exchange command. Be sure to wield the proper weapon when fighting. Hitting a dragon over the head with a bow will simply make him mad, and get you killed. .LP Missile weapons, such as bows, can be wielded, and then the proper missile, in this case an arrow, can be fired across the room into a target. Missiles can be used without the proper missile weapon, but used together they have a greater range and do far more damage. .LP Hits and misses are determined by ability to hit versus armor class. A hit is a strike that does some damage; a miss may in fact reach a target, but fails to do any damage. Higher armor classes make it harder to do damage, and so lead to more misses. .NH 2 Monster Memories .LP There are hundreds of different creatures in the mines of \fImoria\fP, many of which look the same on the screen. The exact species of a creature can be discovered by looking at it. It is also very difficult to keep track of the capabilities of various creatures. Rather than forcing you to keep notes, \fImoria\fP automatically keeps track of your experiences with a particular creature. This is called the monster memory. You monster memory recalls the particular attacks of each creature which you have suffered, as well as recalling if you have observed them to multiply or move erratically, or drop treasure, or many other attributes. .LP If you have killed enough of a particular creature, or suffered enough attacks, recalling the monster memory may also provide you with information not otherwise available, such as a armor class or hit dice. These are not explained, but may be useful to give the relative danger of each creature. This memory can be passed on to a new character even after you die, by means of a reduced save file. .NH 2 Your Weapon .LP Carrying a weapon in your backpack does you no good. You must wield a weapon before it can be used in a fight. A secondary weapon can be kept by wielding it and then using the exchange command. A secondary weapon is not in use, simply ready to be switched with the current weapon if needed. .LP Weapons have two main characteristics, their ability to hit and their ability to do damage, expressed as `(+#,+#)'. A normal weapon would be `(+0,+0)'. Many weapons in \fImoria\fP have magical bonuses to hit and/or do damage. Some weapons are cursed, and have penalties that hurt the player. Cursed weapons cannot be unwielded until the curse is lifted. .LP \fIMoria\fP assumes that your youth in the rough environment near the dungeons has taught you the relative merits of different weapons, and displays as part of their description the damage dice which define their capabilities. The ability to damage is added to the dice roll for that weapon. The dice used for a given weapon is displayed as `#d#'. The first number indicates how many dice to roll, and the second indicates how many sides they have. A \*Q2d6\*U weapon will give damage from 2 to 12, plus any damage bonus. The weight of a weapon is also a consideration. Heavy weapons may hit harder, but they are also harder to use. Depending on your strength and the weight of the weapon, you may get several hits in one turn. .LP Missile booster weapons, such as bows, have their characteristics added to those of the missile used, if the proper weapon/missile combination is used. Also, these weapons will multiply the base damage of the missile by a number from 2 to 4, depending on the strength of the weapon. This multiplier is displayed as `(x#)'. .LP Although you receive any magical bonuses an unidentified weapon may possess when you wield it, those bonuses will not be added in to the displayed values of to-hit and to-dam on your character sheet. You must identify the weapon before the displayed values reflect the real values used. .LP Finally, some rare weapons have special abilities. These are called ego weapons, and are feared by great and meek. An ego sword must be wielded to receive benefit of its abilities. .LP Special weapons are denoted by the following abbreviations: .IP "DF - Defender." A magical weapon that helps the wielder defend himself, thus increasing his/her armor class, and protecting him/her against damage from fire, frost, acid, lightning, and falls. This weapon also will increase your stealth, let you see invisible creatures, protect you from paralyzation attacks, and help you regenerate hit points and mana faster. As a result of the regeneration ability, you will use up food faster than normal while wielding such a weapon. .IP "FB - Frost Brand." A magical weapon of ice that delivers a cold critical to heat based creatures. It will inflict one and a half times the normal damage when used against a heat based creature. .IP "FT - Flame Tongue." A magical weapon of flame that delivers a heat critical to cold based creatures. It will inflict one and a half times the normal damage when used against cold based or inflammable creatures. .IP "HA - Holy Avenger." A Holy Avenger is one of the most powerful of weapons. A Holy Avenger will increase your strength and your armor class. This weapon will do extra damage when used against evil and undead creatures, and will also give you the ability to see invisible creatures. .IP "SA - Slay Animal." A Slay Animal weapon is a special purpose weapon whose sole intent is to destroy all the dangerous animals in the world. An animal is any creature natural to the world. Therefore an orc would not be an animal, but a giant snake would be. This will inflict twice the normal amount of damage when used against an animal. .IP "SD - Slay Dragon." A Slay Dragon weapon is a special purpose weapon whose sole intent is to destroy dragon-kind. Therefore, when used against a dragon, the amount of damage done is four times the normal amount. .IP "SE - Slay Evil." A Slay Evil weapon is a special purpose weapon whose sole intent is to destroy all forms of evil. When used against an evil creature, either alive or undead, the damage done twice the normal amount. .IP "SU - Slay Undead." A Slay Undead weapon is a special purpose weapon whose sole intent is to destroy all forms of undead. This weapon is hated and feared by the intelligent undead, for a single blow from this weapon will inflict three times the normal amount of damage. This weapon also gives you the ability to see invisible creatures, which is especially useful against undead, since many of them are normally invisible. .NH 2 Body and Shield Bashes .LP Weight is the primary factor in being able to bash something, but strength plays a role too. After bashing, a character may be off balance for several rounds depending upon his dexterity. .LP Doors can be broken down by bashing them. Once a door is bashed open, it is forever useless and cannot be closed. .LP Chests too may be bashed open, but be warned that the careless smashing of a chest often ruins the contents. Bashing open a chest will not disarm any traps it may contain, but does allow the strong and ignorant to see what is inside. .LP Finally, a creature may be bashed. If a shield is currently being worn, the bash is a shield bash and will do more damage. In either case, a bash may throw an opponent off balance for a number of rounds, allowing a player to get in a free hit or more. If the player is thrown off balance, his opponent may get free hits on him. This is a risky attack. .NH 2 Your Armor Class .LP Armor class is a number that describes the amount and the quality of armor being worn. Armor class will generally run from about 0 to 60, but could become negative or greater than 60 in rare cases. .LP The larger your armor class, the more protective it is. A negative armor class would actually help get you hit. Armor protects you in three manners. One, it makes you harder to be hit for damage. A hit for no damage is the same as a miss. Two, good armor will absorb some of the damage that your character would have taken. An armor class of 30 would absorb 15% of any damage meant for him. Three, acid damage is reduced by wearing body armor. It is obvious that a high armor class is a must for surviving the lower levels of \fImoria\fP. .LP Each piece of armor has an armor class adjustment, and a magical bonus. Armor bought in town will have these values displayed with its description. Armor that is found within the dungeon must be identified before these values will be displayed. All armor always has the base armor class displayed, to which the bonus is added. It is always possible to figure this out anyway, by watching the effect it has on your displayed armor class. .LP Armor class values are always displayed between a set of brackets as `[#]' or `[#,+#]'. The first value is the armor class of the item. The second number is the magical bonus of the item which is only displayed if known, and will always have a sign preceding the value. There are a few cases where the form `[+#]' is used, meaning the object has no armor class, only a magical armor bonus if worn. Body armor may also have a (-#) displayed in parentheses; this is a penalty to hit, because the bulk of the armor makes it more difficult to swing a weapon freely. .LP Some pieces of armor will possess special abilities denoted by the following abbreviations: .IP "RA - Resist Acid." A character using such an object will take only one-third normal damage from any acid thrown upon him. In addition, armor so enchanted will resist the acid's effects and not be damaged by it. .IP "RC - Resist Cold." A character using a resist cold object will take only one-third damage from frost and cold. .IP "RF - Resist Fire." A character using a resist fire object will take only one-third damage from heat and fire. .IP "RL - Resist Lightning." A character using a resist lightning object will take only one-third damage from electrical attacks. .IP "R - Resistance." A character wearing armor with this ability will have resistance to Acid, Cold, Fire, and Lightning as explained in each part above. .NH 2 Crowns .LP Some crowns also have special magical abilities that improve your chances in a battle. .IP "Crown of Might" This is the great crown of the warriors. The wearer will have an increased strength, dexterity, and constitution, and will also be immune to any foe's attempt to slow or paralyze him or her. .IP "Crown of the Magi" This is the great crown of the wizards. The wearer will have an increased intelligence, and will also be given resistance against fire, frost, acid, and lightning. .IP "Crown of Lordliness" This is the great crown of the priests. The wearer will have an increased wisdom and charisma. .IP "Crown of Seeing" This is the great crown of the rogues. The wearer will be able to see even invisible creatures, and will have an increased ability to locate traps and secret doors. .IP "Crown of Regeneration" This crown will help you regenerate hit points and mana more quickly than normal, allowing you to fight longer before needing to rest. You will use of food faster than normal while wearing this crown because of the regenerative effects. .IP "Crown of Beauty" This crown looks impressive, and will increase your charisma, but is otherwise not useful. .NH 1 Objects Found In The Dungeon .LP The mines are full of objects just waiting to be picked up and used. How did they get there? Well, the main source for useful items are all the foolish adventurers that proceeded into the dungeon before you. They get killed, and the helpful creatures scatter the various treasure throughout the dungeon. Most cursed items are placed there by the joyful evil sorcerers, who enjoy a good joke when it gets you killed. .LP You pick up objects by moving on top of them. You can carry up to 22 different items in your backpack while wearing and wielding many others. Although you are limited to 22 different items, you may be carrying several items of each kind, restricted only by the amount of weight your character can carry. Your weight limit is determined by your strength. Only one object may occupy a given floor location, which may or may not also contain one creature. Doors, traps, and staircases are considered objects for this purpose. .LP If you try to carry more weight than your limit, you will move more slowly than normal until you drop the extra weight. If picking up an object would take you over your weight limit, then you will be asked whether you really want to pick it up. It is a good idea to leave the object alone if you are fleeing from a monster. .LP Many objects found within the dungeon have special commands for their use. Wands must be Aimed, staffs must be Used, scrolls must be Read, and potions must be Quaffed. In any case, you must first be able to carry an object before you can use it. Some objects, such as chests, are very complex. Chests contain other objects and may be trapped, and/or locked. Read the list of player commands carefully for a further understanding of chests. .LP One item in particular will be discussed here. The scroll of \*QWord-of-Recall\*U can be found within the dungeon, or bought at the temple in town. It acts in two manners, depending upon your current location. If read within the dungeon, it will teleport you back to town. If read in town, it will teleport you back down to the deepest level of the dungeon on which your character has previously been. This makes the scroll very useful for getting back to the deeper levels of \fImoria\fP. Once the scroll has been read, it takes a while for the spell to act, so don't expect it to save you in a crisis. .LP The game provides some automatic inscriptions to help you keep track of your possessions. Wands and staves which are known to be empty will be inscribed with \*Qempty\*U. Objects which have been tried at least once, but haven't been identified yet will be inscribed with \*Qtried\*U. Cursed objects are inscribed with \*Qdamned\*U. Also, occasionally you will notice that something in your inventory or equipment list seems to be magical. High level characters are much more likely to notice this than beginning characters. When you do notice this, the item in question will be inscribed with \*Qmagik\*U. .LP And lastly, a final warning: not all objects are what they seem. Skeletons lying peacefully about the dungeon have been known to get up... .NH 2 Cursed Objects .LP Some objects, mainly armor and weapons, have had curses laid upon them. These horrible objects will look like any other normal item, but will detract from your character's stats or abilities if worn. They will also be impossible to remove until a remove curse is done. .LP If you wear or wield a cursed item, you will immediately feel something wrong. The item will also be inscribed \*Qdamned\*U. .NH 2 Mining .LP Much of the treasure within the dungeon can be found only by mining it out of the walls. Many rich strikes exist within each level, but must be found and mined. Quartz veins are the richest, yielding the most metals and gems, but magma veins will have some hordes hidden within. .LP Mining is virtually impossible without a pick or shovel. Picks and shovels have an additional magical ability expressed as `(+#)'. The higher the number, the better the magical digging ability of the tool. A pick or shovel also has plusses to hit and damage, and can be used as a weapon. .LP When a vein of quartz or magma is located, the character should wield his pick or shovel and begin digging out a section. When that section is removed, he should locate another section of the vein, and begin the process again. Since granite rock is much harder to dig through, it is much faster to follow the vein exactly and dig around the granite. There is an option for highlighting magma and quartz. .LP If the character has a scroll or staff of treasure location, he can immediately locate all strikes of treasure within a vein shown on the screen. This makes mining much easier and more profitable. .LP It is sometimes possible to get a character trapped within the dungeon by using various magical spells and items. So it is a very good idea to always carry some kind of digging tool, even when you are not planning on tunneling for treasure. .NH 2 Staircases, Secret Doors, Passages, and Rooms .LP Staircases are the manner in which you get deeper, or climb out of the dungeon. The symbols for the up and down staircases are the same as the commands to use them. A `<' represents an up staircase and a `>' represents a down staircase. You must move your character over the staircase before you can use them. .LP Each level has at least one up staircase, and at least two down staircases. There are no exceptions to this rule. You may have trouble finding some well hidden secret doors, but the stairs are there. .LP Many secret doors are used within the dungeon to confuse and demoralize adventurers foolish enough to enter. But with some luck, and lots of concentration, you can find these secret doors. Secret doors will sometimes hide rooms or corridors, or even entire sections of that level of the dungeon. Sometimes they simply hide small empty closets or even dead ends. .LP Creatures in the dungeon will generally know and use these secret doors. If they leave one open, you will be able to go right through it. If they close it behind them you will have to search for the catch first. Once a secret door has been discovered by you, it is drawn as a known door and no more searching will be required to use it. .NH 1 Winning The Game .LP Once your character has progressed into killing dragons with but a mean glance and snap of his fingers, he may be ready to take on the Balrog. The Balrog will appear on most levels after level 49, so don't go down there until you are ready for him. .LP The Balrog cannot be killed in some of the easier methods used on normal creatures. Because of the Balrog's cunning, he will teleport away to another level if a spell such as destruction is used upon him, and the Balrog cannot be polymorphed, slept, confused, or genocided. Magical spells like coldball are effective against him, as are weapons, but he is difficult to kill, and if allowed to escape to another level can heal himself. .LP If you should actually survive the attempt of killing the Balrog, you will receive the status of WINNER. Since you have defeated the toughest creature alive, your character is ready to retire and cannot be saved. When you quit the game, your character receives a surprise bonus score. .NH 1 Upon Death and Dying .LP If your character falls below 0 hit points, he has died and cannot be restored. A tombstone showing information about your character will be displayed. You are also permitted to get a record of your character, and all your equipment (identified) either on the screen or in a file. .LP Your character will leave behind a reduced save file, which contains only the monster memory and your option choices. It may be restored, in which case the new character is generated exactly as if the file was not there, but the new player will find his monster memory containing all the experience of past incarnations. .NH 1 Wizards .LP There are rumors of \fImoria\fP Wizards which, if asked nicely, can explain details of the \fImoria\fP game that seem complicated to beginners. moria-5.6.debian.1/doc/FEATURES.NEW0000644000175000017500000002741305613574144014541 0ustar pjbpjb You get a warning for spells or prayers beyond your strength. Inventory commands (wear, wield, exchange, take off, drop) now always take one move each. If anything significant happens during that move, such as a monster moving somewhere, the screen will be redisplayed. Inventories are displayed in the top-right corner of the screen, to minimize the number of characters that must be redrawn afterwards, this makes the game much more playable on slow speed modems. When selecting items or spells, you can select with a capital letter to print a description and confirm you really want that one. You can now associate counts with commands. The '?' command shows you the possibilities. In rogue command mode, simply type in the number. In this mode, numbers are no longer simple commands. In original moria command mode, enter a '#' to start a count. There are options (set with the = command) to display weights in an inventory, to highlight mineral seams, to ignore open doors while running, etc. Monster memory: use the / command to access info about a monster after you have seen/killed at least one of them. This can also be accessed from the look 'l' command. Can enter control characters with two keystrokes using ^ key, useful for noisy phone lines? or stupid terminals? 'M'ap command shows reduced size map. 'L' allows you to scroll around entire map. The 'L' command also will now center the character on the screen. Look 'l' views all objects in an arc in the specified direction, or specify '5' and it will look in every direction. Can change your speed in wizard mode. New field in status line, used for rest/paralysed/searching/repeat counts. New field in status line shows speed. Can die of starvation. If carrying too much weight, you will be slowed immediately, the amount slowed depends on how much over the weight limit you are. Can not circle monsters (moving at the same speed as yourself) by moving around them in a diamond pattern. High level monsters have a chance of ignoring your bash, and they also have a chance of recovering immediately even if stunned. You can not bash the Balrog. Can abort rest/repeated command by hitting any character. Every duration affect prints a command when it wears off previously resist heat and resist cold, and perhaps others did not. New find/run algorithm which is much better than the old one. Also, better handling of dangerous conditions that occur during repeat commands/runs. An attack will always stop a repeated command and find/run mode. Can inscribe names onto objects. Some inscriptions are automatic: an empty wand/staff is inscribed 'empty'. An object which is used, but its use does not identify it is inscribed 'tried'. Cursed objects are inscribed 'damned' when identified as cursed. If you detect an object is enchanted, it is inscribed 'magik'. Scrolls have their titles removed after being identified. Scrolls/potions from the store/dungeon can stack after the dungeon item is identified. If you curse/damage a special object, such as a Holy Avenger sword, it will lose its special property. Will automatically save the game correctly if a HANGUP signal is received, i.e. dropped dialup connection, the network crashes, etc. The save file is not a panic save, instead the program plays the game for you (i.e. pretends that you are hitting ESCAPE) until it is safe to save the game. Better handling of inventory/equipment lists, i.e. you can drop items in the equipment list, can identify items in the equipment list, etc. More consistent monster definitions, i.e. creatures with frost attacks always take extra damage from fire (except those that also have fire attacks), and many other fixes. One source for the UNIX/IBM/Atari ST/Amiga/Mac/VMS versions, should make keeping the micro versions up-to-date much easier. The game is smaller and hopefully faster. Savefiles are now relatively machine independent, they should transport from one mini/micro to another without any problems. If you are hallucinating, ^R won't help. Bows can have a plus to damage. These pluses only apply if you are using the bow to fire the appropriate type of missile (arrow/bolt/etc). Can haggle incrementally in the stores, i.e. can increase bid by 10 by typing +10, similarly -10 will decrease bid by 10. Beeps if invalid character entered at most prompts. Can type ^R at any time to refresh the screen. Armor/weapons show their base AC/hit/dam values in their name. Any of RETURN (^M), LF (^J), SPACE, or ESCAPE can be typed at -more- prompts. When droping a group of items, you have the choice of dropping only one, or all of them. There is a small chance that a player will notice that there are unidentified magic items in the inventory. The chance is larger if the item is in the equipment list. Object distribution has been changed so that when you are deep in the dungeon, there are many more high level objects created than low level objects. Monster distribution changed so that when you are deep in the dungeon, you will meet many more high level monsters than low level monsters. Additional spikes make a door harder to open, in a progressively decreasing sequence, that is, the more spikes you add, the less effect each additional spike has. When a stat changes, all abilities/etc that depend on the stat will immediately change. For example, if you CON increases, then your hit points will increase, if your INT/WIS increases then your mana will immediately increase and you will immediately learn new spells/prayers. This makes the Grape Jelly trick completely unnecessary, and, in fact, it will has no effect. Spell/prayer letters never change, i.e. if you know the second spell of a book, it will not be referred to as spell 'a' if you do not know the first spell. When haggling, if you have reach the final offer much more often than you haven't, then the store will give you the benefit of the doubt and go directly to the final price. When wielding a weapon that is too heavy, the to hit penalty will be shown by the 'C' command. It is harder to hit monsters when you can't see them. Perfect stealth is impossible now. Save files are now encrypted. Slay monster items are now slay animal. The previous slay monster item did not work as stated by the documentation, fixing it to work reasonably would have made it too powerful. If picking up an item will slow you down, you are asked if you really want to pick it up. Spells work differently now. You no longer learn them automatically when you gain a level. Instead, 'Study' appears in the status line when are capable of learning new spells. Use the 'G' command to actually learn the spells. The 'G' command can be used anytime that you are eligible to learn new spells, as for example, after quaffing a restore intelligence/wisdom potion. The object naming routines are completely rewritten. This makes the program much smaller. Also, too long names will no longer cause a crash or error, they will be silently truncated as necessary. You can not attack an invisible/unlit monster in a wall by merely moving into the wall, instead you must tunnel into the wall. Since moving into a wall is a free turn, people could take advantage of this while fighting invis monsters by checking all of the walls first. To change the default moria save file name, define the environment variable "MORIA_SAV" to be the full pathname for where you want your save files. "moria -n" will start a new game, and will ignore "moria.save" if it exists Jellies and molds never carry treasure. Recharging a high level wand, or a wand which already has many charges, is much more likely to fail. Elves and half-elves have infravision now. There is no longer a distinction between wizard and god mode; only wizard mode exists now. Also, wizard mode no longer requires a password, and anyone (not just the installer) can enter wizard mode. Hence, wizard now works the same no matter whether you are playing on a micro or a mini. Enter wizard mode by using the ^W command, help is ^H. (Or for the rogue-like option, ^W and \). Missile weapons are much more powerful when used with the proper weapon. For example, firing a bolt from a heavy crossbow multiplies its damage by 4. rounded pebble, iron shot: sling = 2x arrow: short bow = 2x, long bow = 3x, composite bow = 4x bolt: light crossbow = 3x, heavy crossbow = 4x Arrows and bolts appear more often deep in the dungeon. Magical missile weapon prices are more reasonable. The miscellaneous abilities 'fighting', 'bows/throw', 'saving throw', 'disarm', and 'magical device' are all level dependent, i.e. they improve as you gain levels. Formerly, the rate of improvement was independent of class, now, however, the learning rate is clas dependent. For example, warriors gain proficiency at fighting twice as fast as mages/priests now. As a result, high level warriors are better fighters than before, and high level mages/priests do not fight as well as they used to. The complete table is: Magic Saving Fighting Bows Devices Disarm Throw Warrior 4 4 2 2 3 Mage 2 2 4 3 3 Priest 2 2 4 3 3 Rogue 3 4 3 4 3 Ranger 3 4 3 3 3 Paladin 3 3 3 2 3 In all cases, three is equivalent to the old rate. umoria now understands tilde (~) characters at the start of a file name. To resurrect a dead character, use "moria -w filename". New status line shows "Is wizard" if in wizard mode, "Was wizard" if previously was in wizard mode, "Resurrected" if character was resurrected, and "Duplicate" if character is already on the scoreboard. Moved see invisible from slay animal to slay undead, since this makes a lot more sense. Dragon lightning breath attacks can now damage items in your inventory, just like all other dragon breath attacks. New scoreboard code added. It will hold 1000 scores by default, scores for saved characters are listed, can see all scores or just your scores. On multiuser OS's, each user can only have one entry in the scoreboard for each legal race/sex/class combination. The score file format is portable, and should be able to move from one machine to another with no problems. The '-s' option will show all scores in the scoreboard. The '-S' option will show only your scores. The 'V' command will show all scores in the scoreboard. A second 'V' command typed immediately afterwards will show only your scores. Typing '*' for the rest count will make you rest until you reach max mana and max hp. Spikes can now be wielded as a weapon for completeness. Note however that they make terrible weapons. The damage multiplier for bows is now displayed as part of their name. Two new '=' command options: can turn off sound, and can turn off the rest/ repeat counts displayed on the bottom line. The last is useful for those playing at 2400 baud or less, or on very slow machines. Many items are now added to the inventory in a sorted position, e.g. the spell books will always end up in the inventory sorted by their level. This automatic sorting does not work for objects which have a 'color', e.g. potions, wands, staffs, scrolls. Typing RETURN while haggling will default to the last increment/decrement amount used. Umoria 5.4: Prints multiple sentences on the message line if they are short enough. Umoria 5.5: The maximum damage enchantment for a weapon is now equal to its maximum damage, instead of being fixed at 10 (there is a slight chance of enchantment beyond this level); thus daggers are no longer the best weapons for mid-level characters. Umoria 5.5.1: If you inscribe an item with a single digit (using "{" to inscribe), you can refer to that item by the digit when it is in your inventory. You can thus label your pick as item 1, and wield item 1 whenever you need the pick without checking which letter the pick is. The prayers Turn Undead and Holy Word have been strengthened. Creatures with fire attacks now resist your fire attacks, and you will learn this in the recall information. last modified 6/25/94 moria-5.6.debian.1/doc/history0000644000175000017500000001552311074752210014361 0ustar pjbpjb A History of Moria: written by Jim Wilson This history is somewhat biased towards the Umoria versions because those are the versions that I am most familiar with; info for the VMS versions, in particular, may be inaccurate. Moria 4.8: The last version developed by the original authors, R.A. Koeneke, etc., at the Univ Oklahoma. This is written in VMS Pascal, and is only available for VAX/VMS systems. All other versions of moria are based on this program. (Sometimes referred to as VMS Moria 4.8.) Moria UB 5.0: This version was developed at Univ Buffalo, hence the UB in the name. This is also written in VMS Pascal, and is only available for VAX/VMS systems. Some of the distinguishing features of this version are: a Black Market where one can purchase highly enchanted magic items at 100 times normal value, monsters on the town level worth negative experience (Mother and Baby, Small Child), `shadow' Balrogs start appearing at level 50 with the `real' Balrog at level 1200 (this makes it a bit difficult to win). There are also some new items, and many more new monsters. (Sometimes referred to as VMS Moria 5.0 or Moria 5.0. Should not be confused with Umoria 5.x.) This is based on the Moria 4.8 sources. Moria UB 5.1: The latest version of UB Moria. This version is not available outside Univ Buffalo as yet, and I do not know what any of the new features are. Only available for VAX/VMS systems. VMS Moria 6.0: This version was under development at Villanova by Rick Greene. However, it was never completed and was never released. I believe that it was abandoned because Rick lost computer and/or network access. This was based on the Moria UB 5.0 sources. Imoria: This version was developed at the Univ. Washington. It is written in VMS Pascal, and is only available for VAX/VMX systems. I know very little about this version, but have been told by people at U Washington that it is far superior to any other Moria version that currently exists. It has many new monsters, new objects, new races, new classes, new terrain types (like water), etc. The sources are currently available from UBVMS. Imoria 4.9: The latest version of Imoria. PC-Moria 4.00+: This version is a port of the Moria 4.8 Pascal sources to the IBM-PC by John W. DeBoskey. This is a faithful port of the original game, unfortunately, this version has quite a few bugs and hence is not as good as the unrelated PC-Moria 4.87 version. Umoria (UNIX Moria) 4.83/4.85/4.87: This version was developed by Jim Wilson at UC Berkeley. It is written in UNIX/C and is much more portable than the original sources. These sources, at one time or another, were ported to VMS, IBM-PC, Atari ST, Amiga, Macintosh, Apple IIGS, VM/SP, Archimedes, are probably others too. This version fixes very many bugs, spelling errors, and inconsistencies in the original Moria 4.8 sources. This version has no help facility like the original program. It has character rerolling (in the later versions), but few other changes from the original game. (This version has many names, e.g. Umoria 4.87, UNIX Moria 4.87, PC-Moria 4.83, PC-Moria 4.873, Mac Moria 4.87, etc. Just about anything with a .83/.85/.87 in the name is a version of this program.) This is based on the Moria 4.8 sources. PC-Moria 4.83/4.873: This version was developed by Don Kneller, based on the Umoria sources. These sources are identical except that they will compile on machines with 16 bit integers, had many changes to reduce program size, and introduced the reduced map display. (Note: PC-Moria 4.83 is extremely buggy, and is unplayable. I strongly recommend that you upgrade to a newer version if you are still playing it.) Amiga Moria v3.0: This version was written by Richard and Bryan Henderson of Kettering, Ohio. It is based on the Umoria 4.85 sources. This version has bitmapped graphics, unlike the ascii graphics of all other versions. It has weapons of Godly Might (which make one practically invicible) and some other changes that make it far far easier than all other Moria versions. It also has several new monsters, such as Lavender Leprechauns. Sources for this version were never released. BRUCE Moria: This version was developed by Christopher J. Stuart at Monash University, Clayton, Victoria Australia. This version has many great new features: monster memories, look any direction code, settable options, better run/find code, can center character on screen, stat code rewritten to fix bugs, rudimentory help facility added, plus many other enhancements. This was considered an experimental version, and source never publicly released. This was based on the Umoria 4.85 sources. UMoria 5.x: This version is under developement by Jim Wilson at Cygnus Support. It has unified source for the UNIX/IBM-PC/Atari/Mac/VMS/Amiga ports of Umoria 4.87. It includes many new features borrowed from BRUCE Moria, many more bug fixes, all floating point code eliminated, many changes that affect play balance (hopefully for the better), many type/structure changes to reduce game size and allow fixes for pervasive bugs. See the doc/FEATURES.NEW file for a list of most user visible changes. (Sometimes called Umoria 5.0, Moria 5.0, Moria 5.x. Should not be confused with Moria UB 5.0.) Umoria 5.6 The latest version of Umoria 5.x. David Grabiner has taken over Umoria 5.x development but has made only minor changes. Umoria 5.6 is released under the GNU General Public License. Vertical position indicates roughly when the versions were made available, although the scale is not very accurate. 1983 Moria 1.0 | 1985 Moria 4.8 / \ 1987 UMoria 4.83 ------ ----------------------\ / \ | \ / ------- PC-Moria 4.83 | | UMoria 4.85 | | | / | \ | | Moria UB 5.0 1988 /------ | ------ | | | / | UMoria 4.87 | | | | BRUCE Moria | \ | | | Amiga Moria | | PC-Moria 4.873 | |---\ (surviving) | | / | | \ 1989 | /----------/ | | VMS Moria 6.0 | / | | (defunct) 1990 Umoria 5.0 | | | Imoria 4.9 Moria UB 5.1 | | | 1994 Umoria 5.5.1 (alive and well) (alive and well) | 2008 Umoria 5.6 | (alive and well) moria-5.6.debian.1/doc/exp.doc0000644000175000017500000001367205613574145014236 0ustar pjbpjbAddendum to the Moria manual Proposed Contribution. Written by Mike Marcelais North Carolina School of Science And Math mrm@odin.ncssm.edu games@odin.ncssm.edu 1. Experience All characters receive experience during the game. Experience determines your level, which determines hit points, mana points, spells, abilities, etc. The amount of experience required to advance a level is a base value (shown below) plus a penalty for race and class. 1.1 Calculating Experience Levels Base Experience Lv Exp to Adv Lv Exp to Adv Lv Exp to Adv 1 10 14 1,400 27 35,000 2 25 15 1,800 28 50,000 3 45 16 2,300 29 75,000 4 70 17 2,900 30 100,000 5 100 18 3,600 31 150,000 6 140 19 4,400 32 200,000 7 200 20 5,400 33 300,000 8 280 21 6,800 34 400,000 9 380 22 8,400 35 500,000 10 500 23 10,200 36 750,000 11 650 24 12,500 37 1,500,000 12 850 25 17,500 38 2,500,000 13 1,100 26 25,000 39 5,000,000 Maximum level is 40 and maximum experience is 9,999,999 There are percent penalties for various races and classes to help even them out. The table below lists all the penalties. Human 0% Warrior 0% Half-Elf 10% Mage 30% Elf 20% Priest 20% Halfling 10% Rogue 0% Gnome 25% Ranger 40% Dwarf 20% Paladin 35% Half-Orc 10% Half-Troll 20% For example: For a 10'th level Gnomish Mage to achieve 11'th level needs: 500 * 1.25 * 1.30 = 812.5 (base) (gnome) (mage) Note: Even for the worst case (Gnomish Ranger) it is still possible to achieve the 40th level. (5,000,000*1.25*1.40=8,750,000 experience) The program internally keeps experience out to the fourth decimal place even though it only displays the integer portion on the screen. 1.2 Getting Experience There are many ways to gain experience. This list shows a few. 1. Defeating monsters 2. Disarming traps 3. Picking locks 4. Using a scroll, potion, staff, wand, or rod for the first time and discovering what it did. 5. Casting a spell successfully for the first time. 6. Drinking a potion of gain experience or gain level 1.3 Titles Each experience level has a title which is displayed under your name and class. Below is a listing of all the titles for each level and class. Warrior Mage Priest Rogue Ranger Paladin 1 Rookie Novice Believer Vagabond Runner(1st) Gallant 2 Private Apprentice Acolyte(1st) Footpad Runner(2nd) Keeper(1st) 3 Soldier Trickster-1 Acolyte(2nd) Cutpurse Runner(3rd) Keeper(2nd) 4 Mercenary Trickster-2 Acolyte(3rd) Robber Strider(1st) Keeper(3rd) 5 Veteran(1st) Trickster-3 Adept(1st) Burglar Strider(2nd) Keeper(4th) 6 Veteran(2nd) Cabalist-1 Adept(2nd) Filcher Strider(3rd) Keeper(5th) 7 Veteran(3rd) Cabalist-2 Adept(3rd) Sharper Scout(1st) Keeper(6th) 8 Warrior(1st) Cabalist-3 Priest(1st) Magsman Scout(2nd) Keeper(7th) 9 Warrior(2nd) Visionist Priest(2nd) Common Rogue Scout(3rd) Keeper(8th) 10 Warrior(3rd) Phantasmist Priest(3rd) Rogue(1st) Scout(4th) Keeper(9th) 11 Warrior(4th) Shadowist Priest(4th) Rogue(2nd) Scout(5th) Protector-1 12 Swordsman-1 Spellbinder Priest(5th) Rogue(3rd) Courser(1st) Protector-2 13 Swordsman-2 Illusionist Priest(6th) Rogue(4th) Courser(2nd) Protector-3 14 Swordsman-3 Evoker(1st) Priest(7th) Rogue(5th) Courser(3rd) Protector-4 15 Hero Evoker(2nd) Priest(8th) Rogue(6th) Courser(4th) Protector-5 16 Swashbuckler Evoker(3rd) Priest(9th) Rogue(7th) Courser(5th) Protector-6 17 Myrmidon Evoker(4th) Curate(1st) Rogue(8th) Tracker(1st) Protector-7 18 Champion-1 Conjurer Curate(2nd) Rogue(9th) Tracker(2nd) Protector-8 19 Champion-2 Theurgist Curate(3rd) Master Rogue Tracker(3rd) Defender-1 20 Champion-3 Thaumaturge Curate(4th) Expert Rogue Tracker(4th) Defender-2 21 Superhero Magician Curate(5th) Senior Rogue Tracker(5th) Defender-3 22 Knight Enchanter Curate(6th) Chief Rogue Tracker(6th) Defender-4 23 Superior Knt Warlock Curate(7th) Prime Rogue Tracker(7th) Defender-5 24 Gallant Knt Sorcerer Curate(8th) Low Thief Tracker(8th) Defender-6 25 Knt Errant Necromancer Curate(9th) Thief(1st) Tracker(9th) Defender-7 26 Guardian Knt Mage(1st) Canon(1st) Thief(2nd) Guide(1st) Defender-8 27 Baron Mage(2nd) Canon(2nd) Thief(3rd) Guide(2nd) Warder(1st) 28 Duke Mage(3rd) Canon(3rd) Thief(4th) Guide(3rd) Warder(2nd) 29 Lord(1st) Mage(4th) Canon(4th) Thief(5th) Guide(4th) Warder(3rd) 30 Lord(2nd) Mage(5th) Canon(5th) Thief(6th) Guide(5th) Warder(4th) 31 Lord(3rd) Wizard(1st) Low Lama Thief(7th) Guide(6th) Warder(5th) 32 Lord(4th) Wizard(2nd) Lama-1 Thief(8th) Guide(7th) Warder(6th) 33 Lord(5th) Wizard(3rd) Lama-2 Thief(9th) Guide(8th) Warder(7th) 34 Lord(6th) Wizard(4th) Lama-3 High Thief Guide(9th) Warder(8th) 35 Lord(7th) Wizard(5th) High Lama Master Thief Pathfinder-1 Warder(9th) 36 Lord(8th) Wizard(6th) Great Lama Executioner Pathfinder-2 Guardian 37 Lord(9th) Wizard(7th) Patriarch Low Assassin Pathfinder-3 Chevalier 38 Lord Gallant Wizard(8th) High Priest Assassin Ranger Justiciar 39 Lord Keeper Wizard(9th) Great Priest High AssassinHigh Ranger Paladin 40 Lord Noble Wizard Lord Noble Priest Guildmaster Ranger Lord High Lord moria-5.6.debian.1/compile/0000755000175000017500000000000010760060056013613 5ustar pjbpjbmoria-5.6.debian.1/ChangeLog.19900000644000175000017500000014462205613574241014356 0ustar pjbpjb::::::: 1990 :::::::: ------------ 1/1 creatures.c: in mon_cast_spell(), must update_mon() to light monsters before they cast a spell ------------- 1/2 moria1.c: inven_command(), could not wear item which replaced equip item if inven full, only fail if inven_check_num fails for torches misc2.c: change spacing for stats on change_character page, was printing in last column for max stat moria2.c: tunnel(), if no shovel/pick, divide total tabil chance by two monsters.c: change eye-sight and sleep values for consistency, as noted by djgrabin help.c: change the monster recall so that it lists high level monsters first creature.c: when monster bashes down a door, call disturb() to halt resting io.c: fix msg_print() so that -more- is always printed on screen, fix put_buffer() so that does not fail if col argument greater than 79/80 misc1.c: change chance for ego weapons/missiles to 3*special/2 instead of just special, needed because treasure distribution change has made ego weapons not as common as before --------- 1/11 monsters.c: let nether wraith phase, set Black/Red/Multi ancient dragons to a sleep value of 700 creature.c: increase r_attacks if either notice true or r_attacks is nonzero (i.e. it has been noticed before) moria2.c: move_char(), when step back after setting off a falling rock trap, check to see if have stepped back onto another trap moria1.c: inven_command(), when restart it after taking off an item, don't print the 'have to drop something' message because that is confusing misc2.c: modify_stat(), could overflow 118 when increasing stats, add extra case to enforce max of 118 --------- 1/12 all: apply william setzer's objdes() diffs, 500K patch file, change version number to 5.0.10 and distribute desc.c, misc2.c, store1.c: remove several obsolete uses of index(), insert_num() no longer used anywhere constant.h, desc.c: change ID_TRIED,ID_KNOWN1 to OD_TRIED,OD_KNOWN1 desc.c: eliminate titles[], rename title_space[] to titles[] all: fixed lint errors all: make sure that all objdes() strings are bigvtype desc.c: fix printing of bows/arrows/picks, needed new p1_use define, and rearrange code in objdes() switch statement treasur1.c, treasur2.c: remove -100 tohit from books, was being printed, and is silly anyways constant.h, externs.h, save.c, treasur2.c: change object_ident[] from MAX_OBJECTS to OBJECT_IDENT_SIZE = 7*64, see object_offset() in desc.c to see why this is necessary ---------- 1/13 externs.h, misc2.c, store1.c: deleted obsolete references to treasure_type desc.c: always print toac field if known2 and non-negative config.h, io.c, misc1.c: eliminated BUGGY_CURSES define, caused too much trouble, just assume that can never print in last column of screen constant.h, desc.c, misc1.c, moria2.c, spells.c, treasur1.c, types.h: created special_names table to hold all possible name2 strings, name2 changed to an int8u which holds index to special_names table externs.h, main.c, treasure1.c: sort_objects() function deleted, sorting now done by init_t_level using O(n) bin sort, into sorted_objects[] array files.c, misc2.c: object_list[] references that assumed it was sorted now indirect through sorted_objects[] array main.c, variable.c: player_init indexes now point into object_list instead of inventory_init ------- 1/14 constant.h, externs.h, main.c, store1.c, treasur1.c, treasur2.c, variable.c: deleted inventory_init array, stores objects now in object_list, MAX_OBJECT adjusted, MAX_DUNGEON_OBJ defined, store_choice[] fixed all: put all objects in object_list, trap_list, door_list, store_door, gold_list, up_stair, down_stair, rubble, much, blank_treasure, scare_monster are not separate variables anymore all: invcopy now takes an object_list index as second parameter, name field deleted from inven_type and fields rearranged ----------- 1/15 store1.c: search_list() deleted, use i_ptr->index instead to get raw item cost save.c: obsolete treasure_type references deleted, save files work again creature.c, magic.c, misc2.c, prayer.c, save.c, wands.c: fixed long/short problems with shift, mostly change (1 << i) to (1L << i) all: add new register declaration, check indentation, fix 32/16bit int problems constant.h: change version number to 5.0.11 ------------- 1/17 spells.c: aggravate was not initiallized in aggravate_monster() monsters.c: novice rogue now evil like other rogues misc2.c: 2 "... learn ... new spells ..." messages changed to print prayers instead for priests moria2.c: drop_throw(), "The %s hits %s" changed to "The %s hits the %s." many: fixed problems with setting of free_turn_flag ----------- 1/19 misc2.c: fix inven_carry(), to stack store/dungeon items properly desc.c: objdes(), set p1_use = IGNORED for food and potions, changed is_a_vowel(tmp_val[1]) to [2] moria2.c: "exceed weight limit?" message now prints item name also desc.c, spells.c, staffs.c, wands.c: empty wands are not incribed empty if known2, empty removed when wands are recharged desc.c: put spaces between inscribed words dungeon.c: always inscribe majik when character notices this, not just for inventory items as that helps priests more than fighters store1.c: sell_price(), succeed only if both item->cost and item_value() are positive creature.c: don't increase a number of attacks when monster repelled in make_attack(), i.e. no damage done so shouldn't learn about damage moria1.c: regenhp and regenmana, could get chp/cmana equal to max and _frac non-zero, change c > max test to c >= max test constant.h, dungeon.c, misc2.c: hp and mana were printed while in store/inv, fix calc_hitpoints() and calc_mana() to set flags instead of printing, in dungeon.c, checks flags and print values ---------- 1/20 store2.c: redisplay store prices if charisma changes during the inven_command calls (actually just redraw everything) moria2.c: monster_death(), dump must be set to 0 is number is 0 constant.h, moria2.c, recall.c, spells.c: recall printing of treasure changed, instead of setting CM_ bits, store largest number of treasure ever generated in those 5 CM_TREASURE bits, changed monster_death() to set the bits the new way, changed uses of monster_death() to replace old treasure bits with new ones, the vague print out treasure amounts replace with printout of precise number of treasures generated externs.h, moria2.c: monster_death() changed to int32 monster_death() moria1.c: new_spot() contained line of code "i = randint(10)" that did not belong there, was formerly testing code desc.c: objdes(), force zero charges to always print, also, always print digging plusses even if zero main.c: items that initialize players inventory are marked store_bought(), this is needed so that dagger/armor bonuses will be shown for them desc.c: objdes(), fixed printing of doors, known1() clear the tried flag, magic_init() don't let scroll names end with a blank misc2.c: gain_spells(), call calc_mana() if py.misc.mana == 0, this is for characters who did not know any spells before the 'G' command, can't gain spells if blind/no light/confused moria1.c: infinite loop entered with 'id' and screen_change, also, 'n' to the continuing with inventory prompt did not work, must clear doing_inven before returning from inven_command() in these cases desc.c: identify(), don't merge items in equip list, only merge items that are single stackable misc2.c: inven_carry(), inven_check_num(), fix item stacking, items can only stack if they are both identified or both unknown (store items are always identified) constant.h: change version number to 5.0.12 and distribute ------------ 1/21 desc.c: objdes() bug, change p1_use = IGNORED to p1_use == IGNORED moria2.c: move_char(), moving into a wall is no longer a free turn misc2.c: gain_spells(), priests no longer need book before can learn spells from it, mages still need the books, calc_spells() delete unused var spells[], remove limit of 23 from number of new spells dungeon.c: made scribe_object() a free turn again recall.c: only print monster speed if at least one movement flag known unix.c: missing */ after Gakk!! -CJS-. desc.c: stacking did not work right, fixed known1_p() to return OD_KNOWN1 instead of TRUE for store items, so that known1_p() == known1_p() will work consistently monsters.c: creeping coins hit instead of bite, and touch instead of breath variable.c: fixed problems with temple/alchemist store inventories desc.c, store1.c: fixed food prices, only check unknown if subval puts it among the molds/mushrooms ------------- 1/24 misc2.c, types.h: change inscrip back to char *, fix inscribe() to malloc space for string, and then copy inscription into the malloced space, save.c: fixed (compatibly) to write/read new inscriptions desc.c: free malloced inscription space in invcopy death.c, misc1.c: delete max tcptr code constant.h, desc.c, misc1.c: define new const ID_SHOW_TOHIT, in magic_treasure set this bit for every weapon,digging tool,missile,bow, in objdes() print out tohit/todam if this bit set and object identified, this makes it easy to tell ident weapons from unident weapons main.c: char_inven_init() must set ID_SHOW_TOHIT flag for initial weapon death.c, constant.h, misc1.c: change MAX_TALLOC from 225 to 150, delete temporary code which printed out max tcptr values misc2.c: allow inscriptions of up to 24 characters constant.h: change version number to 5.0.13 and distribute -------------- 1/26 wizard.c: wizard_create(), initialize the name2 and inscrip fields to 0, init the ident field to known2 and storebought constant.h: changed MAX_TITLES from 60 to 45 desc.c: magic_init(), wrote to a char *tmp; modified to write to a vtype string recall.c: change printing of treasure again, only print 'sometimes' is 60% is only bit set, otherwise always print 'often' if only one object, for two objects, print 'often' only if 60% and 90% are only bits set scrolls.c: recharge scrolls not used up when read, fixed setting of used_up spells.c: res = TRUE; moved out of if-stmt so only needed once treasure.c: change wiz obj name from "& wizard object" to "{wizard object}" ---------- 1/29 moria2.c: tunnel(), give player attack on creature if it is in the way misc2.c: gain_spell(), remove limit of 22 on learning spells, fix print_spells so that it will only show the first 22 spells constant.h, desc.c, misc1.c: change ID_SHOW_TOHIT to ID_SHOW_HITDAM, set this bit for gauntlet/rings of slaying, and irritation/enveloping cloaks, fix objdes() so that it only prints both tohit/todam if this bit is set otherwise, only prints one number, if either of tohit/todam nonzero desc.c, treasure.c: remove "the entrance to the " from store doors and put in objdes() in desc.c misc2.c: put_misc2(), add "Exp to Adv." to character display constant.h, desc.c, misc1.c: added defines for ID_NOSHOW_P1 and ID_SHOW_P1 to improve printing of object names, objdes() always prints p1 if ID_SHOW_P1 set, and never prints it if NOSHOW set, these override the default p1_use setting, NOSHOW added to sustain stat rings, SHOW added to clumsy/weak gloves, boots of speed/stealth/slowness, helms of int/wis/infra/might/lordliness/magi/beauty/seeing/ stupid/dull/weak/ugly, cloaks of stealth creature.c: increase effect of aggravate_monster attack from range of 5 to 20 spells.c: dispel_creature(), prt_exp() was only called when visible creatures died, now always called when creature dies misc1.c: added messages to compact_objects() and compact_monsters() so that can tell if they are ever called store1.c: rings/amulets which are not known2 now have base value from object list instead of real value moria2.c, staffs.c, wands.c: cast level to int, so that calculations will be done with signed arithmetic, in openobject() change chance of opening a chest, instead of -2*level use -level, this help eliminate chests which are impossible to open --------- 1/30 recall.c: print ' at normal speed' for monsters with mspeed = 1 --------- 2/10 spells.c: turn_undead, speed_monsters, sleep_monsters2, and dispel_creature modified so that they only affect creatures in los of player externs.h, misc2.c, variable.c: new array spell_order[], holds order in which spells are learned, in calc_spell() spells are now remembered in the order that they were learned, and forgotten in the reverse order learned, in gain_spell() must modify spell_order when spell learned main.c: spell_order initialized in inven_char_init to all 99s save.c: save/restore spell_order, for patch_level <= 13 savefiles create a reasonable spell_order on the fly misc2.c: was erasing wrong line in gain_spells, change `j+2' to `j+1' all: change file names to be 8.3 characters long constant.h: change version number to 5.0.14 and release ---------- 2/10 dungeon.c: change rogue-like wiz help key from ^? to \ all: merged in Mac sources, all initialized variables are now in variable.c, rearranged directory structure ---------- 2/11 all: merged in VMS sources changed to 5.0.15 and distribute --------- 2/13 moria2.c: carry(), printed 'worth of emeralds..' removed '.' from string desc.c: crowns did not print out AC because it is zero, add special case to objdes() so that tval == 33 (crowns) always have AC printed out, change (+5 charges) to (5 charges) ----------- 2/14 moria2.c: inven_throw() created second copy of pointer to malloced inscription, it now creates new inscription for new object moria1.c: inven_command(), wear option copied malloced inscription, create new inscription for new object misc2.c: inven_destroy(), free inscription of just deleted object, clear inscrip pointer of last objects previous location, so that it will not be freed, inven_drop(), create new inscription for new item, inven_carry() create new inscription for new item, scribe_object() free space for old insription since it is deleted config.h, externs.h, misc2.c, moria1.c: rename remove() to takeoff() to avoid naming conflict with library routines externs.h, misc2.c, store1.c: deleted join_names(), no longer doing anything useful, and was wrongly creating duplicate pointers to malloc blocks moria2.c: make moving into walls a free turn again, but player can not attack invisible creatures in walls by moving into wall (hence preventing him from using 6 free turns to search for invis creature), must tunnel into wall instead, which always takes a turn dungeon.c, externs.h, moria2.c: pass direction to tunnel() instead of point digging to, eliminates a lot of duplicate code, tunnel() now checks confusion, and tries to tunnel in random direction if confused treasure.c: clone monster wands changed from level 2 to level 15, makes them recharge less, max 6 new charges instead of max 18 new charges files/version.hlp: add Dan Bernstein's name to credits magic.c, variable.c, wands.c: change stinking cloud from 16 to 12 damage as it was too close to lightning bolt at 18, reduce mana for mage/ranger from 4/6 to 3/5 moria1.c: show_inven() and show_equip(), don't print first two spaces when col is zero, since will blank the whole screen anyways moria2.c: py_attack(), only cleared confuse_monster flag if monster survived attack, now always clear this flag and try to confuse monster -------------- 2/16 all: add in diffs to get MSDOS version working again, add files from binary PC-Moria distribution types.h: for PC, use 'unsigned char var : 1' to reduce sizeof cave_type from 5 to 4 desc.c, misc1.c, misc2.c, moria1.c, moria2.c, save.c, wizard.c, types.h: change inven_type inscrip field from pointer to an 13 char array, mallocing storage for inscriptions does not work, results in dangling pointers when inven_types are copied save.c: add 'time' to savefiles, use this to calculate age of savefile instead of using stat, much more portable, and prevents cheating, if time is newer than current time, set age to 0, when save file check to see if current time greater than start time, if not, then save start time plus one day in save file mac.c: delete getfileage since no longer used recall.c: change knowdamage(), add damage parameter so that higher damage attacks take longer to learn than lower damage attacks monsters.c: jellies and molds no longer have treasure save.c: two places have (*str != NULL), changed to (*str != '\0') save.c: remove support for pre 5.0.13 versions, rd_item() no longer needs patch_level monsters.c: move crystal ooze from level 31 to level 40, to make raising crystal oozes for treasure much more dangerous --------------- 2/19 all: added defines for tvals, and substituted every where in program ---------- 2/21 ms_misc.c, io.c: remove all uses of mvprintw() for ibmpc port, since PC curses also pulls in the fp library if mvprintw is used dungeon.c: in the recover from blindness code, the disturb() call must be before the creatures(FALSE) call getch.c, io.c, Makefile: more fixes for the VMS port of umoria, new getch.c file, and new copy of (4.87) io.c file ---------- 2/22 all: check again for numbers that should be constants constant.h: change version number to 5.0.17 externs.h, main.c, moria2.c, signals.c, treasure.c: compile with gcc -Wall and fix all reported errors --------- 2/26 prayer.c: change (!class[].spell == PRIEST) to (class[].spell != PRIEST) store2.c: for good bargaining, use final_ask not min_buy in sell_haggle() dungeon.c: change "Sorry.." to "Sorry." misc1.c: for gloves/gauntlets, p1 and ID_SHOW_P1 set in wrong place creature.c: make_attack(), creature could be visible at start of attack but invisible at end due to a teleport, set notice/visible appropriately before monster attacks, and don't use m_ptr->ml afterwards monsters.c: creeping coins always carry gold now, 1d2 for copper, 1d2+60 for silver, and 1d2+90 for gold treasure.c, wizard.c: change name of wizard items to empty string, and inscribe them with "wizard item" desc.c: problem with rubble/stone-to-mud, change rubble case from like stairs to be like doors moria1.c: show_equip(), change non-weight limit from 57 to 60, change weight limit from 49 to 52 chars, for show_inven(), change limits from 66/74 to 68/76 characters creature.c, magic.c, prayer.c, spells.c, wands.c: fix get_flags(), fire_ball(), fire_bolt() and breath() to use defined constants for attack types moria1.c: show_inven(), show_equip(), make sure that col never less than zero all: merged in Atari ST diffs from Stephen A. Jacobs --------------- 2/27 creature.c: fixed bug with doors, always open/light door instead of only opening/lighting them when in los of player moria2.c: when bash open door, only break it 50% of the time to be consistent with code in creature.c all: delete some obsolete files, annotate a few others, put README files in the subdirectories to explain what is present save.c: fix old savefile compatibility code to work with new version numbers constants.h: change version number to 5.1.0 and publicly announce ---------- 2/28 recall.c: creature is worth... sprintf() call used %ld instead of %d moria2.c: look_ray(), every place GRADF multiplied by y, cast it to long to prevent overflow of 16 bit ints ms_misc.c: were still two refs to 'byteint', changed to 'int8u' MLINK.LNK: updated for umoria5.0, add undef and recall, change treasur[12] to treasure create.c: delete sleep(1) call in character rerolling code death.c: put "#ifndef L_SET" around the #define L_SET io.c: ifdef out suspend code, for USG systems with BSDisms that have SIGTSTP defined but don't actually implement it io.c: change name of variable 'border' to 'screen_border' to avoid naming conflict on SGI/SYS V machine INSTALL: moved from doc subdirectory to root directory, and brought up to date ---------------- 3/1 misc2.c: two places where (1L << j) occurred, and j could be 99 (unknown spell from spell_order[]), this is an undefined operation, fixed source to not shift if j == 99 ------------------- 3/3 misc1.c: set_options(), typing '-' on line 0 gave error, change i=max to i=max-1 store1.c: item_value(), calculating digging tool values wrong, subtract off objects initial p1 plusses before multiplying p1 by 100 dungeon.c: for paralysed/resting, move cursor to player before refresh call creature.c: disenchanter bat attacks could put tohit/todam/toac below zero, fixed so that they can not go below zero moria1.c: if have MAX_SHORT hp/mana, then could get overflow in regenhp/mana routines, added checks for overflow dungeon.c, io.c: save on EOF code did not work, in inkey(), remove casts to char in eof test, remove call to feof(), in dungeon(), add !eof_flag to innermost while loop to ensure it exits on error save.c: in sv_write(), clear death flag if eof_flag or panic_save set, so player can restart game to see tombstone main.c: set death flag if hit points are negative, can happen if a HANGUP savefile or panic savefile is restored save.c: if get_char(), don't overwrite died_from string if player is dead main.c: if specify -r or -o, force rogue_like to appropriate value after read the savefile, since get_char() will modify rogue_like_commands moria1.c: search(), "have found a trap.." fixed, removed extra period monsters.c: added CD_NO_SLEEP flag to jellies, oozes, elementals and the gelatinous cube dungeon.c: fix "which level" wizard prompt, limited to level 99 max ----------- 3/4 all: merged in more Mac diffs, Mac version should compile now wizard.c: stealth max 87 should be 18 in printed string desc.c: identify(), if cursed incscribe with ID_DAMD, unsample(), do not clear the ID_DAMD flag, since an unsampled item is still cursed config: change version number to 5.1.1 and release ------------ 3/5 monsters.c: added CD_NO_SLEEP flag to creeping coins recall.c: recharge(), change chance of failure from randint((num+40)/10)=1 to randint((num+40-i_ptr->p1-i_ptr->level)/10)=1 to make it harder to recharge high level and highlly charged wands recall.c: change j from int to int32u, since it is used with flag fields, change two %d uses of it to %ld desc.c: objdes(), don't print ID_TRIED value for store bought items moria2.c: a slow dart trap now has no effect if have free action io.c: must ifdef out the tbuf.c_cc code, since this causes the program to fail for some reason --------------- 3/13 signals.c: add void to USG signal_hander definition externs, ms_misc.c: move fopen declaration from externs.h to ms_misc.c, and make static, and make FILE * not struct _iobuf ms_ansi.c: include stdio.h generate.c: change #if DEBUG to #ifdef DEBUG config.h, generate.c, types.h: added ifdefs for IBMPC_TURBO_C --------- 3/16 moria1.c: inven_command() "Wear" prompt changed to "Wear/Wield" monsters.c: earth elementals/spirits can now move through walls spells.c: wall_build(), for earth elementals, increase their hit points files.c: helpfile(), can ESC out now spells.c: cloning a monster will wake it up now dungeon.c: allow two-char control character sequences to be used with repeated commands (deleted else from "else if (command == '^')") roglcmds.hlp: document how to avoid problem with repeated dig left command, i.e. '13^H' doesn't work, type ^ then H, or type SPACE then ^H --------- 3/19 unix.c: initialize num_chars to zero in check_input(), in case FIONREAD absent ---------- 3/21 all: fix most SYS_V lint errors ----------- 3/23 dungeon.c, io.c: calling inkey() when check_input true is wrong since it traps ^R and does other stuff, instead call new function raw_inkey(), which only calls getch io.c: flush(), occasionally caused loss of output, instead of using fancy ioctls, drain input by using check_input/raw_inkey --------- 3/25 dungeon.c, io.c, unix.c, atarist.c: AIX can't check to see if input is pending, but can do non-blocking read, so check_input changed so that it consumes input when called constant.h: change version number to 5.1.2 and distribute -------- 3/26 save.c: when resurrect, clear poisoned flag and food flag to prevent character from immediately dying again main.c, misc2.c, unix.c, save.c: fix some BSD lint errors moria1.c: remove unnecessary flush() call from take_hit() creatures.c, misc1.c, externs.h, variable.c: fixed problem with calls to compact_monster() within creatures() by adding a horrible hack, new variable hack_monptr defined to hold current creature() monptr ---------- 3/27 variable.c: add infra 3/2 for elf/half-elf, were both previously 0, increase gnome infra from 3 to 4 config.h, death.c, dungeon.c, externs.h, main.c, misc2.c, signals.c: modify wizard mode code, no longer need password or correct UID to enter, prints disclaimer then asks for confirmation atarist.c, death.c, misc2.c, ms_misc.c, save.c, signals.c: eliminate all getuid() etc. code, only place these are still used is in main.c and unix.c all: merge wizard/god mode, god mode nolonger exists io.c, unix.c: problems with flush() on EOF, don't call check_input if EOF, also, check_input returns zero if got an error on the read, also inkey() clears msg_flag on EOF to prevent infinite loops exit_game/ msg_print/inkey/exit_game/etc... moria2.c: monster_death(), increase tries from 10 to 20 so that treasure will be created more often constant.h: increase MAX_MALLOC from 101 to 125 to reduce compacting monsters messages, increase MAX_TALLOC from 150 to 175 because it is possible to get compacting objects message during level generation constant.h: BTH_HIT deleted, no longer used ----------- 3/28 moria2.c: facts(), multiply damage for missile by 2/3/4 instead of adding when use proper weapons, makes missiles much more useful save.c: write store info and time into save file even if dead, so that can be restored on a resurrection constant.h: change version to 5.1.3 -------- 3/30 constant.h, externs.h, files.c, misc2.c, moria1.c, moria2.c, staffs.c, wands.c, variable.c: modify how misc abilities vary with level, new variable class_level_adj, which holds the new adjustment values, bth, bthb, device, disarm and save affected externs.h, misc2.c, moria2.c: critical_hits() has fourth paramter, that indicates whether to use CLA_BTH or CLA_BTHB class level adj moria2.c: penalty for attacking invisible creatures modified, was minus lev * BTH_LEV_ADJ-1, now minus lev * BTH_LEV_ADJ/2, hence warriors have less penalty than mages/priests creature.c, externs.h, misc2.c, moria2.c: test_hit has a fifth paramter, that indicates whether to use CLA_BTH or CLA_BTHB (or even CLA_SAVE) io.c: add abort() calls to move_cursor_relative(), print(), and put_buffer() to help find bugs in the code save.c: eliminate support for versions 5.0.11 to 5.0.13 misc2.c: get_spell(), only say 'unknown spell' if it is actually an alphabetic character typed treasure.c: delete one ring of adornment and one amulet of adornment, add arrows at level 15, and bolts at level 25 --------- 3/31 store1.c: change missile cost to 5*pluses instead of 10*pluses, since missiles appear in groups of 20 or so, this is comparable to normal weapons which are 100*pluses distribute 5.1.3 sources ---------- 4/3 externs.h: ifdef out definition of errno for MSDOS io.c: moved process.h include for MSDOS from middle of file to start io.c: in print(), put_buffer(), and move_cursor_relative(), clear msg_flag before printing error message, prevents problems with '-more-' prompt recall.c: roff_recall(), don't set normal movement bit near beginning, also delete code that prints 'never moves' if all move bits clear spells.c: teleport monster will wake it up scrolls.c: reading a second word of recall scroll does not reset timer spells.c: wall building now heals Xorns in addition to earth elementals spells.c: drain life damage increased from 50 to 75, to match other 50th level wand damages constant.h, creature.c, moria2.c, variable.c: defined new class level adj CLA_MISC_HIT and replace all test_hit uses of CLA_SAVE with this, document that this is identical to save, and assumes all values same treasure.c: two potions named poison, change first to weakness (lose str) ---------- 4/4 save.c: add some __GNUC__ ifdefs so that the UNIX style code will be used, not the code for the broken atari st MWC libraries ---------- 4/6 unix.c: two include files, sys/time.h and sys/resource.h are actually BSD specific, put #ifndef USG around them ---------- 4/9 desc.c: remove all uses of "%+d", because AtariST/MWC and convex and probably others do not support it spells.c: replace_spot(), clear lr flag, so that after destruction scroll, destroyed areas will not be lit by a light scroll in a room creature.c: let monsters eat other monsters of equal exp, helps prevent using oozes as treasure factories moria2.c: mon_take_hit(), if kill Balrog, always update recall info even if Balrog invisible, since will always know it was the Balrog (winner!) recall.c: sleep values too hard to learn, change test from r_wake > sleep to (r_wake*r_wake)>sleep -------- 4/13 creature.c, moria2.c: mon_take_hit() was called within creatures() when monsters were trapped inside a wall, bracket call in creature.c with code to set hack_monptr, and add code to mon_take_hit() to check it creature.c: add code at end of creatures() loop to fix2_delete_monster() in case monster died during movement (maybe it was in a wall?) externs.h: add DGUX to USG ifdef for the 'extern int sprintf()' declaration io.c: added code to save/restore local mode word of tty driver, i.e. TIOCLSET and TIOCLGET ioctl calls save.c: for atarist && __GNUC__, call fopen with "rb" and "wb" for binary mode io.c, unix.c: for atarist && __GNUC__, don't include externs.h: define sprintf as int (), if defined(atarist) ------------ 4/14 externs.h, unix.c: three new functions tilde(), topen(), and tfopen() which perform ~ expansion for file names, in externs.h, define open to topen and fopen to tfopen for unix machines config.h, dungeon.c, main.c, save.c, unix.c: add support for ANDREW distributed file system, SECURE define in config.h, disallows inferior shells, also instead of giving up setuid priviledges at start, calls ANDREW library functions bePlayer(), beGame(), and Authenticate() unix.c: add ifdefs to use select() when compiling for xenix ------------- 4/15 creature.c, externs.h, files.c, io.c, main.c, misc1.c, moria2.c, recall.c, save.c, treasure.c: more Atari ST MWC fixes, eliminate fdopen(), make loc_symbol() return unsigned char, all (var & long_const) constructs assign long const to temp var first, ------------ 4/16 Makefile: fixed problems with 'make install' ----------- 4/19 atarist.c: add #include at start, and #endif at end misc2.c: tohit_adj() toac_adj() todis_adj() todam_adj() all used cur_stat instead of use_stat like they should have ---------- 4/20 moria2.c: mon_take_hit code of 4/13 wrong, use monptr instead of i at end misc2.c: remembering code wrong, add (i < 32) to stop it at end of spell list moria1.c: when inven full and take off object, check for object under player before allowing/asking her to drop object save.c: for atarist MWC port, ifdef out all of the open() calls, and only leave the fopen() stuff in misc1.c: compact_monsters(), don't set delete_any if fix1_delete_monster() is called, because it does not decrement mfptr, call abort() if cur_dis goes below zero (i.e. can't delete any monsters) all: run lint on 4.3BSD and SYS V constant.h: change version number to 5.1.4 and distribute ----------- 4/27 dungeon.c: add prt_map() at top after creatures(FALSE) call for ATARIST_MWC, fixes display problems for some reason ---------- 5/1 moria1.c: inven_command(), clear msg line is ESC typed at "Drop all?" prompt ---------- 5/3 all: eliminated upd_log(), and plog variable doc/*: update all documentation, except moria.ms ---------- 5/4 all: visit every subdirectory, create README or ERRORS files as needed, make everything as up to do as possible, split files greater than 60K so that they can be posted to comp.sources.games easily all: deleted all tmp.* files externs.h, moria1.c, moria2.c, et al: moved functions out of moria1.c and moria2.c to reduce their size to less than 60K, many functions not moved were made static dungeon.c, externs.h, main.c, misc2.c, save.c, variable.c: new variable to_be_wizard, allows resurrect without entering wizard mode, resurrect sets noscore = 0x1, wizard mode sets noscore = 0x2, prt_winner prints "Is/Was wizard" or "Resurrect" is noscore set ----------- 5/5 misc1.c: moved see invisible from slay animal to slay undead weapons doc/moria.ms: updated documentation to reflect changes from 4.873 to 5.1, added section which explains crowns, added some sections from Chris J Stuart's BRUCE Moria's documentation --------- 5/7 monsters.c: ogre mage is now evil files.c: added extern int error for MSDOS moria.ms: proof read it again misc1.c: reduce plus to dam for slay dragon arrows from +10 to +3, no longer need such high damages because ptodam is multiplied now when used with right weapon Makefile: test and fix 'make install' ibmpc/ms_ansi.c: change two escape characters to \033 mac/moria.r: change many control characters to \xxx, update version info strings to 5.1.5 constant.h: change the version number to 5.1.5 and distribute --------- 5/9 constant.h, mac/moria.r: change the version number to 5.2.0 save.c: fix support code for 5.0 savefiles, because of minor version number change, update compatibility code for 5.1 and 5.2 savefiles save.c: save/restore value of died_from string ------- 5/10 scrnmgr.r, scrntest.r: these files had control characters also, changed '...' to \311 resource.hqx: recompiled the mac resource files macscore.c, mac.c: changed control characters '...' to \311 all: distribute version 5.2.0 ----------- 5/14 death.c, externs.h, io.c, ms_misc.c: Turbo C changes, void sleep() instead of unsigned sleep(), don't call reset_term() before exiting, ifdef out definition of sleep() in ms_misc.c, declare signal handler as void not int generate.c, types.h: change IBMPC_TURBO_C defines to the proper TURBOC define io.c: shell_out(), MSDOS code parameter to inkey() call deleted externs.h: count_msg_print() changed from (int) to (char *) io.c: get_check(), add code to use 'y' if LINT_ARGS defined, pause_exit() add code to use 'delay' for MSDOS machines ms_misc.c: clear_screen(0,0) changed to clear_screen() main.c: set stack size for TURBOC by declaring the _stksize variable misc2.c: player_saves(), split expression up because MPW C couldn't handle it save.c: include time.h for for the Mac, delete var 'i' in save_char (unused), get_char() add code for MAC to return FALSE if savefile doesn't exist mac.c: add call to initsavedefaults() in main() mac/ERRORS: document problem with mac Makefile -------- 5/15 externs.h: remove decl of py_bash(), which is in moria2.c and static --------- 5/17 dungeon.c: move search_off() call after check_view(), as panel_* variables must be valid before search_off() is called -------- 5/18 all: 7 files did not end with newlines, 5 hqx files, and origcmds.hlp, misc/README also did not end with a newline -------- 5/21 constant.h, version.hlp, moria.r: change version number to 5.2.1 ScrnMgr.doc: split all lines greater than 80 characters, to make the file more portable --------- 5/22 death.c: in mac sources, there was a 'true' instead of a 'TRUE' ms_misc.c: Turbo C sscanf() incorrectly reads a newline from a blank line, add check for newline to code that reads configuration file spells.c: door_creation(), called popt() before calling delete_object() which could then invalidate the value returned by popt, moved popt() call after the delete_object() call ----------- 5/25 creature.c: fix the invincible/invisible monster bug, multiply_monster() was creating children on top of the parent, thus killing the parent for carnivorous monsters death.c, externs.h, generate.c, io.c, main.c, ms_misc.c, signals.c, types.h: change all TURBOC defines to __TURBOC__ util/printit: new version of the printit program by Carl Hommel, fixed up to be somewhat more portable and to use only moria defined constants -------- 5/27 player.c, tables.c, variable.c: Turbo C can not accept any file with more than 64K global variables, so variable.c split into three parts, also updated all makefiles to refer to all three files mac files: all three mac Makefiles modified to delete obsolete references to CInterface.o and CRuntime.o, scrnmgr Makefile modified to automatically combine the two ScrnMgr.c parts, README updated to document a problem with the Makefile not appending resources and text files sometimes ---------- 5/31 all: released umoria 5.2.1 ibmpc/ms_misc.c: corrected warn() function to use va_list, the old function was not strictly correct ---------- 6/4 misc2.c: prt_stat_block() must also call prt_study() misc2.c: random_object() could create objects outside of map boudaries, added an in_bounds() call to fix ------------- 6/6 main.c: changed 'if (p = getenv(...))' to 'if ((p = getenv(...)) != NULL)' to avoid compiler warnings moria1.c: rest_on(), add check to make sure rest_num fits in short ibmpc/umoria.prj: new file, a project file for Turbo C 2.0 ------------- 6/9 io.c: HP-UX does not have VEOL2, added #ifdef VEOL2 around its use dungeon.c: clear message line after change_character(), since as ESCAPE exit does not moria1.c: for 'x' and 'w' commands, clear heavy_weapon flag before calling check_strength, so that always get heavy message when wielding heavy weapon, and never get light message when wielding light weapon scrolls.c: identify scroll can move arbitrarily far after ident_spell(), replace simple 'moved one down' check with loop to search until found main.c: fixed starup code so that don't get 'savefile doesn't exist' message anymore when starting a new game all: apply fix to all uses of long constant with & | << operators to avoid a Mark Williams C bug on the Atari ST externs.h, files.c: removed MSDOS declaration of errno from files.c, and remove ifndef MSDOS from errno decl in externs.h misc1.c: changed name of variable 'clock' to 'clock_var' to avoid problem with a mac compiler (not sure which one) io.c: every io.c file, remove '\0' as alias for ESCAPE from get_com() and get_comdir() (MAC only function) moria1.c: light_dam() calls inven_damage(set_lightning_destroy, 3) which gives it a small chance of destroying objects in player's pack, this makes it just like the other *_dam() functions spells.c: teleport_to(), add call to in_bound() to make sure player will be teleported to somewhere inside the dungeon ------------- 6/10 config.h: add note about using GCC on an Atari ST main.c, save.c, undef.c: eliminated the unused _new_log() function death.c, dungeon.c, externs.h, save.c, undef.c, variable.c: eliminated the mostly unused log_index variable, the few uses of it were replaced with references to character_saved externs.h, files.c, io.c, undef.c: init_scorefile() implemented, same as in umoria 4.87 main.c, undef.c: eliminate unused function init_files() constant.h, moria.r, version.hlp: change version number to 5.2.2 ----------- 6/11 ibmpc/ms_misc.c: added space to GRAPHICS scanf, to try to eliminate problem with Turco C death.c, externs.h, files.c, save.c, variable.c: extensive changes to implement the scorefile, total_points(), highscores(), display_ scores(), set_fileptr(), rd_highscore(), and wr_highscore() defined scorefile holds 1000 entries max, has one sex/race/class entry per non-zero uid, has live characters also unix/Makefile: fix the treatment of score file, don't copy over old one, just use touch to create one if it doesn't exist undef.c: finally eliminated ---------- 6/13 all: lint under 4.3 BSD and AIX 2.2.1 (SYS V) scores: readd scores file, since it makes micro distributions much easier death.c: modify savefile for single user machine, so that it tries to prevent a single character from appearing multiple times in the savefile, checks for identical names, and killed by = (saved) player.c: eliminated the unused dsp_race[] array death.c: added code to implement flock() for systems which don't have it, based on code written by CJS for BRUCE Moria ---------- 6/17 all: fixes for VMS, define USG for VMS, merge in fixes from Todd Pierzina ---------- 6/23 scrolls.c: for curse weapon, call py_bonuses(-1) before clear flags so that attributes will be turned off moria1.c: calc_bonuses(), handle AC just like everything else, previously did not add in AC bonus if armor was cursed creature.c, moria2.c: doors weren't being broken when bashed, change "randint(2) - 1" to "1 - randint(2)" ----------- 7/14 all: merge in some changes indiciated by warnings/prototypes generated by MSC 5.x recall.c: compute monster kill exp in long, to avoid overflow of int all: added AMIGA support amiga/: new directory to hold support files for the amiga main.c: variable result was not initialized to false ------------- 7/15 all: merge in more VMS patches death.c, dungeon.c: fixed display_scores() and 'V' command problems creature.c, dungeon.c, misc2.c, moria1.c: new feature '*' rest until reach max mana and hp, print error message for illegal rest count all: removed improper define of NULL, new define CNIL for (char *)0, used instead of NULL where appropriate, eliminate strange include orders that the previous NULL define required io.c: ifdefed out the include for termio.h, as this caused it to be included twice on some systems (curses.h includes it also) causing problems macrsrc.h: changed MAX_RESTART from 37 to 36 --------- 7/21 ms_misc.c: fixed reading of empty lines from config file for Turbo C -------- 7/22 io.c: fix Amiga code for flush() types.h: reduce size of cave_type structure for Amiga/Aztec C 5.0 death.c: fix display_scores(), so that it only shows entries belonging to current player when show_player is true --------- 8/29 misc2.c: deleted some redundant code in gain_spells() where it calculates which spells a player can learn spells.c: recharge(), could call randint() with 0 or negative numbers, check for these cases before calling randint() --------- 9/8 moria1.c: inven_command(), when drop/remove object and inven/equip are both empty, set inven weight to zero, just to be safe dungeon.c: jamdoor(), when jam a door, decrement inven_weight by weight of one spike moria1.c: inven_command(), make spikes wieldable objects, fight with them like missile weapons, i.e. they disappear after use desc.c: objdes(), add damage multiplier of bows to their name externs.h, io.c, misc1.c, save.c variable.c: new option sound_beep_flag, so that players can turn off bad character beep if desired desc.c, misc2.c: modify known1_p() to return TRUE for objects which never have a color, modify objdes() to work with the new convention, modify inven_carry() so that objects are added to the inventory sorted by subval if they are known1_p() ---------- 9/9 misc1.c: add_food(), fix so that does not use f_ptr->slow to set f_ptr->food value, this makes it much less likely to overflow the food level misc2.c: inven_carry(), yesterday's insert in order fix does not work for items which can be unknown1p, only insert items ordered by subval if they are always known1p, i.e. object_offset() returns -1 externs.h, misc1.c, misc2.c, save.c variable.c: new option display rest/repeat counts, since these counts make resting at 1200 baud or less unbearably slow, people need to be able to turn them off store2.c: get_haggle(), let RET default to the last inc/dec amount when haggling misc1.c: compact_monsters(), return FALSE if could not delete any monsters instead of aborting, popm() return -1 if could not allocate monster (i.e. compact_monsters() failed), place_win_monster() abort if popm() fails which should never happen, place_monster() externs.h: place_monster() now int type not void, creature.c, misc1.c, spells.c: fix users of place_monster() to check result, and fail if place_monster() failed, really only necessary for the calls in creature.c, these fixes fix the monster list overflow bug dungeon.c, externs.h, misc1.c: change compact_monsters() from static to extern, call it from within main loop in dungeon.c if there are less than 10 spaces left in the monster list, compact_monsters() is much more likely to be successful when called here than when called from creatures() ----------- 9/11 signals.c: delete extra definition of error_sig for ATARIST_MWC atari_st/README: update with GCC and Turbo C info files.c: fix typo, filname1 -> filename1 --------------- 9/18 mac.c, ScrnMgr1.c: replace uses of KeyMapLM with GetKeys() call ------------- 9/19 misc1.c: m_bonus(), could overflow on 16 bit machines when level >= 263 when calculating stand_dev death.c, externs.h, save.c: store the encryption byte for each savefile record immediately before it in the scorefile, makes the scorefile more robust in the face of a system crash, rd_highscore(), wr_highscore() no longer pass the encryption byte death.c: added version numbers to the savefile death.c, externs.h, save.c, variable.c: add max_score to savefile, which is the maximum score the character has reached so far, total_points() modified to use the larger of the computed score, and the value of max_score, this prevents a "(saved)" message on the score file for a dead character, which died having fewer points than when it was last saved ----------- 9/26 death.c, externs.h, main.c, save.c, types.h, variable.c: new global variable birth_date, set to time when character created, saved in save files and scorefile, when loading character check to see if the a character in the scorefile has the same race/sex/class/uid/birth_date and its died_from is not "(saved)", in which case this character will not be scored misc2.c: print "Duplicate" on screen for such duplicate characters all: update all documentation, README, and other misc descriptive files all: add fixes for Atari ST/Turbo C 2.0 all: lint on Sun3/uVAX/MIPS/RT_PC recall.c: when printing out depth of monster, print Balrog as 50 not 100 ----------- 10/3 all: fix all problems reported by maniscan/cshar, except for control-L characters on a line by themselves ----------- 10/7 creature.c: mon_move(), cast m_ptr->fy-1 to int, so that negative values will correctly compare to it, in the wall building code spoilers: new file, lists spell damages misc2.c: prt_experience(), always check whether exp is greater than max_exp, previously did not when player was at level 40 creature.c: mon_move(), set the recall CM_ATTACK_ONLY bit when a monster should have moved but did not, instead of the old method of setting it when a non-moving monster attacked store2.c: get_haggle(), fix bugs in the automatic increment code, also, when reach final offer, set the automatic increment to the required diff, so that player need only hit return to bid the final amount moria2.c: tunnel(), before checking for tunneling into a invisible monster, check to make sure player is tunneling somewhere which has an effect, otherwise, player can use this to 'detect' invisible monsters in open spaces by trying to tunnel there moria1.c: calc_bonuses(), base AC should always be visible, as long as the item is not cursed ------- 10/8 spells.c: td_destroy2(), should not destroy chests, not disarms and unlocks them instead misc2.c: put_misc3(), clear_from(14) not 13, was clearing the gold value files.c: file_character(), add the "Max Exp" and "Exp to Adv" fields to the info written to a file, to match the on screen display files.c: file_character(), set fd to -1, not NULL, code was closing stdin (== 0 == NULL) when could not open file death.c: exit_game(), clear character_saved before calling highscores(), prevents inkey() from recursively calling exit_game() when eof on stdin has been detected all: released 5.2.2 sources ----------- 10/23 death.c: highscores(), must do fseek() after reaching EOF before changing read/write mode, previously only did this for VMS, now do this for all systems ----------- 10/26 config.h, death.c, io.c: fix VMS errors, declare 'string' in death.c duplicate_character(), fix typos in other files dungeon.c: for VMS, after calling kbhit(), must consume one character vms/Makefile: fixed, mostly change constants.h to constant.h ------------ 10/30 death.c, externs.h, files.c, save.c: define STDIO_LOADED after including stdio.h, then use it to control declarations in externs.h constant.h, death.c: define SCOREFILE_SIZE as 1000, and use it in death.c moria2.c: cast_spell(), when don't have enough mana, use 'gods may think you presumptuous' message instead of 'summon your limited strength' ----------- 11/4 ibmpc/moria.cnf: add ^M, since otherwise MSDOS moria can't read file properly io.c: include stdio.h explicitly, and define STDIO_LOADED, so savefile can be closed when shelling out store2.c: get_haggle(), clear increment when invalid increment entered store2.c, variables.c: last_store_inc contradictory declarations, changed both to int16 externs, misc2.c, sets.c, spells.c: set_*_destroy changed to take inven_type pointer instead of tval, modified so that (Rx) items won't be destroyed by attacks of type x death.c: for single user systems, use birth_date instead of name when looking for matching characters in savefile death.c: MSDOS setmode() needs file descriptor, not FILE pointer files/*: removed all TABS, since some systems do not handle them properly, specifically, Turbo C on the Atari ST and IBM-PC misc1.c: rings of searching cost was 100*p1, amulet of searching cost 20*p1, change both to 50*p1 mac/macio.c, ibmpc/tcio.c: modify beep() so that it uses the new option flag desc.c: changed the (*2) string for bows to (x2) spells.c: slow monster and confuse monster modified to wake up monster if the attacks fails spells.c: wall_to_mud() and dispel_creature(), print messages even if monster not visible since the effects are visible/audible moria2.c: for fire/acid/gas traps, print the trap message first, and then damage an item treasure.c: change name of lose memories potion to lose experience, so it won't be confused with monster memories spells.c: trap_creation(), don't create a trap under the player, to prevent strange occurances such as ending up under a falling rock moria2.c: tunnel(), when wielding heavy weapon, make tunneling more difficult ----------- 11/6 vms/getch.c: New code for kb_hit(), which was tested and works under VMS 5.2 the old code did not work for VMS 5.2 ----------- 11/9 misc1.c: compact_monsters(), distance test was backwards!, now delete monsters farther away first, allow a final pass with distance of 0, never delete the Balrog during compaction ---------- 11/21 doc/history: rewrote history file to bring it up-to-date misc2.c: gain_spells(), don't need to be able to read spell books if learning priestly spells, don't fail if blind or no light death.c: fix #ifdef typo around include ----------- 12/1 store2.c: when good bargainer, change string to "final offer", and allow return to accept final offer player.c: change rogue start inv from Soft Armor to Cloak, so that it is the same as the other non-Warrior classes dungeon.c: decrement command count after do_command() instead of before, so that all counted commands will work right, this fixes 3^P --------- 12/5 death.c: display_scores(), fix VMS bug, truncate uid to a short before comparing against the uid in the score file record, also move the uid computation outside the loop to speedup the procedure io.c: put_buffer (), for Atari ST, was printing the untruncated out_str instead of tmp_str --------- 12/14 atari_st/curscomp/curses.[ch], death.c, files.c, io.c, signals.c: add Atari ST TC fixes for the new (in 5.2.2) code moria-5.6.debian.1/shortnam.sed0000644000175000017500000002540705613574236014536 0ustar pjbpjbs/CM_CARRY_GOLD/ACM_CARRY_GOLD/g s/CM_CARRY_OBJ/BCM_CARRY_OBJ/g s/CS_BR_FIRE/ACS_BR_FIRE/g s/CS_BR_FROST/BCS_BR_FROST/g s/CS_SUMMON_MON/ACS_SUMMON_MON/g s/CS_SUMMON_UND/BCS_SUMMON_UND/g s/CS_TEL_LONG/ACS_TEL_LONG/g s/CS_TEL_SHORT/BCS_TEL_SHORT/g s/CS_TEL_TO/CCS_TEL_TO/g s/CUR_VERSION_MAJ/ACUR_VERSION_MAJ/g s/CUR_VERSION_MIN/BCUR_VERSION_MIN/g s/DUN_STR_DEN/ADUN_STR_DEN/g s/DUN_STR_MAG/BDUN_STR_MAG/g s/DUN_STR_MC/CDUN_STR_MC/g s/DUN_STR_QC/DDUN_STR_QC/g s/DUN_STR_QUA/EDUN_STR_QUA/g s/DUN_STR_RNG/FDUN_STR_RNG/g s/DUN_TUN_CHG/ADUN_TUN_CHG/g s/DUN_TUN_CON/BDUN_TUN_CON/g s/DUN_TUN_JCT/CDUN_TUN_JCT/g s/DUN_TUN_PEN/DDUN_TUN_PEN/g s/DUN_TUN_RND/EDUN_TUN_RND/g s/ID_SHOW_HITDAM/AID_SHOW_HITDAM/g s/ID_SHOW_P1/BID_SHOW_P1/g s/INVEN_ARM/AINVEN_ARM/g s/INVEN_ARRAY_SIZE/BINVEN_ARRAY_SIZE/g s/INVEN_AUX/CINVEN_AUX/g s/INVEN_HANDS/AINVEN_HANDS/g s/INVEN_HEAD/BINVEN_HEAD/g s/INVEN_LEFT/AINVEN_LEFT/g s/INVEN_LIGHT/BINVEN_LIGHT/g s/ITEM_GROUP_MAX/AITEM_GROUP_MAX/g s/ITEM_GROUP_MIN/BITEM_GROUP_MIN/g s/ITEM_NEVER_STACK_MAX/AITEM_NEVER_STACK_MAX/g s/ITEM_NEVER_STACK_MIN/BITEM_NEVER_STACK_MIN/g s/ITEM_SINGLE_STACK_MAX/AITEM_SINGLE_STACK_MAX/g s/ITEM_SINGLE_STACK_MIN/BITEM_SINGLE_STACK_MIN/g s/MAX_CAVE_FLOOR/AMAX_CAVE_FLOOR/g s/MAX_CAVE_ROOM/BMAX_CAVE_ROOM/g s/MAX_MALLOC/AMAX_MALLOC/g s/AMAX_MALLOC_CHANCE/BMAX_MALLOC_CHANCE/g s/MAX_MONS_LEVEL/AMAX_MONS_LEVEL/g s/MAX_MON_MULT/BMAX_MON_MULT/g s/MAX_MON_NATTACK/CMAX_MON_NATTACK/g s/MAX_OBJECTS/AMAX_OBJECTS/g s/MAX_OBJ_LEVEL/BMAX_OBJ_LEVEL/g s/MIN_MALLOC_LEVEL/AMIN_MALLOC_LEVEL/g s/MIN_MALLOC_TD/BMIN_MALLOC_TD/g s/MIN_MALLOC_TN/CMIN_MALLOC_TN/g s/MORIA_HELP/AMORIA_HELP/g s/MORIA_HOU/BMORIA_HOU/g s/MORIA_ORIG_HELP/AMORIA_ORIG_HELP/g s/MORIA_OWIZ_HELP/BMORIA_OWIZ_HELP/g s/MORIA_SAV/AMORIA_SAV/g s/AMORIA_SAVE/BMORIA_SAVE/g s/AMORIA_SAV_NAME/CMORIA_SAV_NAME/g s/MORIA_TOP/AMORIA_TOP/g s/AMORIA_TOP_NAME/BMORIA_TOP_NAME/g s/MORIA_WELCOME/AMORIA_WELCOME/g s/MORIA_WIZ_HELP/BMORIA_WIZ_HELP/g s/NORMAL_TABLE_SD/ANORMAL_TABLE_SD/g s/NORMAL_TABLE_SIZE/BNORMAL_TABLE_SIZE/g s/OBJ_BASE_MAGIC/AOBJ_BASE_MAGIC/g s/OBJ_BASE_MAX/BOBJ_BASE_MAX/g s/OBJ_DIV_CURSED/AOBJ_DIV_CURSED/g s/OBJ_DIV_SPECIAL/BOBJ_DIV_SPECIAL/g s/OBJ_STD_ADJ/AOBJ_STD_ADJ/g s/OBJ_STD_MIN/BOBJ_STD_MIN/g s/PLAYER_EXIT_PAUSE/APLAYER_EXIT_PAUSE/g s/PLAYER_FOOD_ALERT/BPLAYER_FOOD_ALERT/g s/PLAYER_FOOD_FAINT/CPLAYER_FOOD_FAINT/g s/PLAYER_FOOD_FULL/DPLAYER_FOOD_FULL/g s/PLAYER_FOOD_MAX/EPLAYER_FOOD_MAX/g s/PLAYER_FOOD_WEAK/FPLAYER_FOOD_WEAK/g s/PLAYER_REGEN_FAINT/GPLAYER_REGEN_FAINT/g s/PLAYER_REGEN_HPBASE/HPLAYER_REGEN_HPBASE/g s/PLAYER_REGEN_MNBASE/IPLAYER_REGEN_MNBASE/g s/PLAYER_REGEN_NORMAL/JPLAYER_REGEN_NORMAL/g s/PLAYER_REGEN_WEAK/KPLAYER_REGEN_WEAK/g s/PLAYER_WEIGHT_CAP/LPLAYER_WEIGHT_CAP/g s/SCREEN_HEIGHT/ASCREEN_HEIGHT/g s/SCREEN_WIDTH/BSCREEN_WIDTH/g s/SN_SLAYING/ASN_SLAYING/g s/SN_SLAY_ANIMAL/BSN_SLAY_ANIMAL/g s/SN_SLAY_EVIL/CSN_SLAY_EVIL/g s/SN_SLOWNESS/ASN_SLOWNESS/g s/SN_SLOW_DESCENT/BSN_SLOW_DESCENT/g s/STORE_MAX_INVEN/ASTORE_MAX_INVEN/g s/STORE_MIN_INVEN/BSTORE_MIN_INVEN/g s/TR_RES_ACID/ATR_RES_ACID/g s/TR_RES_COLD/BTR_RES_COLD/g s/TR_RES_FIRE/CTR_RES_FIRE/g s/TR_RES_LIGHT/DTR_RES_LIGHT/g s/TR_SLAY_ANIMAL/ATR_SLAY_ANIMAL/g s/TR_SLAY_DRAGON/BTR_SLAY_DRAGON/g s/TR_SLAY_EVIL/CTR_SLAY_EVIL/g s/TR_SLAY_UNDEAD/DTR_SLAY_UNDEAD/g s/TV_MAX_ENCHANT/ATV_MAX_ENCHANT/g s/TV_MAX_OBJECT/BTV_MAX_OBJECT/g s/TV_MAX_PICK_UP/CTV_MAX_PICK_UP/g s/TV_MAX_VISIBLE/DTV_MAX_VISIBLE/g s/TV_MAX_WEAR/ETV_MAX_WEAR/g s/TV_MIN_DOORS/ATV_MIN_DOORS/g s/TV_MIN_ENCHANT/BTV_MIN_ENCHANT/g s/TV_MIN_VISIBLE/CTV_MIN_VISIBLE/g s/TV_MIN_WEAR/DTV_MIN_WEAR/g s/TV_POTION1/ATV_POTION1/g s/TV_POTION2/BTV_POTION2/g s/TV_SCROLL1/ATV_SCROLL1/g s/TV_SCROLL2/BTV_SCROLL2/g s/WIN_MON_APPEAR/AWIN_MON_APPEAR/g s/WIN_MON_TOT/BWIN_MON_TOT/g s/aggravate/Aaggravate/g s/Aaggravate_monster/Baggravate_monster/g s/attack_blows/Aattack_blows/g s/attack_desc/Battack_desc/g s/attack_dice/Cattack_dice/g s/attack_sides/Dattack_sides/g s/attack_type/Eattack_type/g s/background/Abackground/g s/Abackground_type/Bbackground_type/g s/change_character/Achange_character/g s/change_name/Bchange_name/g s/change_speed/Cchange_speed/g s/change_trap/Dchange_trap/g s/character_generated/Acharacter_generated/g s/character_saved/Bcharacter_saved/g s/confuse_monster/Aconfuse_monster/g s/confused/Bconfused/g s/create_character/Acreate_character/g s/create_food/Bcreate_food/g s/creature_type/Acreature_type/g s/creatures/Bcreatures/g s/default_dir/Adefault_dir/g s/default_signals/Bdefault_signals/g s/delete_monster/Adelete_monster/g s/delete_object/Bdelete_object/g s/detect_evil/Adetect_evil/g s/detect_inv/Bdetect_inv/g s/detect_inv2/Cdetect_inv2/g s/detect_invisible/Ddetect_invisible/g s/detect_monsters/Edetect_monsters/g s/detect_object/Fdetect_object/g s/detect_sdoor/Gdetect_sdoor/g s/detect_trap/Hdetect_trap/g s/detect_treasure/Idetect_treasure/g s/disarm_all/Adisarm_all/g s/disarm_trap/Bdisarm_trap/g s/insert_lnum/Ainsert_lnum/g s/insert_num/Binsert_num/g s/insert_str/Cinsert_str/g s/insult_cur/Ainsult_cur/g s/insult_max/Binsult_max/g s/inven_carry/Ainven_carry/g s/inven_check_num/Binven_check_num/g s/inven_check_weight/Cinven_check_weight/g s/inven_command/Dinven_command/g s/inven_ctr/Einven_ctr/g s/inven_damage/Ainven_damage/g s/inven_destroy/Binven_destroy/g s/inven_drop/Cinven_drop/g s/inven_throw/Ainven_throw/g s/inven_type/Binven_type/g s/log_max_dlv/Alog_max_dlv/g s/log_max_exp/Blog_max_exp/g s/magic_shop/Amagic_shop/g s/magic_spell/Bmagic_spell/g s/max_panel_cols/Amax_panel_cols/g s/max_panel_rows/Bmax_panel_rows/g s/monster_attacks/Amonster_attacks/g s/monster_death/Bmonster_death/g s/monster_name/Cmonster_name/g s/monster_type/Dmonster_type/g s/move_cursor/Amove_cursor/g s/Amove_cursor_relative/Bmove_cursor_relative/g s/msdos_init/Amsdos_init/g s/msdos_intro/Bmsdos_intro/g s/next_to_corr/Anext_to_corr/g s/next_to_wall/Bnext_to_wall/g s/next_to_walls/Cnext_to_walls/g s/object_ident/Aobject_ident/g s/object_list/Bobject_list/g s/panel_col/Apanel_col/g s/Apanel_col_max/Bpanel_col_max/g s/Apanel_col_min/Cpanel_col_min/g s/Apanel_col_prt/Dpanel_col_prt/g s/panel_contains/Epanel_contains/g s/panel_row/Apanel_row/g s/Apanel_row_max/Bpanel_row_max/g s/Apanel_row_min/Cpanel_row_min/g s/Apanel_row_prt/Dpanel_row_prt/g s/player_exp/Aplayer_exp/g s/player_hp/Bplayer_hp/g s/player_init/Cplayer_init/g s/player_light/Dplayer_light/g s/player_saves/Eplayer_saves/g s/player_type/Fplayer_type/g s/protect_evil/Aprotect_evil/g s/protection/Bprotection/g s/prt_stat/Aprt_stat/g s/Aprt_stat_block/Bprt_stat_block/g s/Aprt_state/Cprt_state/g s/put_misc1/Aput_misc1/g s/put_misc2/Bput_misc2/g s/put_misc3/Cput_misc3/g s/remove_curse/Aremove_curse/g s/remove_fear/Bremove_fear/g s/resist_cold/Aresist_cold/g s/resist_heat/Bresist_heat/g s/restore_level/Arestore_level/g s/restore_screen/Brestore_screen/g s/restore_signals/Crestore_signals/g s/restore_term/Drestore_term/g s/screen_change/Ascreen_change/g s/screen_map/Bscreen_map/g s/search_flag/Asearch_flag/g s/search_off/Bsearch_off/g s/search_on/Csearch_on/g s/set_acid_affect/Aset_acid_affect/g s/set_acid_destroy/Bset_acid_destroy/g s/set_corr/Aset_corr/g s/Aset_corrodes/Bset_corrodes/g s/sleep_monster/Asleep_monster/g s/Asleep_monsters1/Bsleep_monsters1/g s/Asleep_monsters2/Csleep_monsters2/g s/speed_monster/Aspeed_monster/g s/Aspeed_monsters/Bspeed_monsters/g s/store_bought/Astore_bought/g s/Astore_bought_p/Bstore_bought_p/g s/store_buy/Cstore_buy/g s/store_carry/Astore_carry/g s/store_check_num/Bstore_check_num/g s/store_choice/Cstore_choice/g s/store_ctr/Dstore_ctr/g s/store_init/Astore_init/g s/store_inven/Bstore_inven/g s/summon_monster/Asummon_monster/g s/summon_object/Bsummon_object/g s/summon_undead/Csummon_undead/g s/sustain_chr/Asustain_chr/g s/sustain_con/Bsustain_con/g s/sustain_dex/Csustain_dex/g s/sustain_int/Dsustain_int/g s/sustain_str/Esustain_str/g s/sustain_wis/Fsustain_wis/g s/td_destroy/Atd_destroy/g s/Atd_destroy2/Btd_destroy2/g s/teleport/Ateleport/g s/Ateleport_away/Bteleport_away/g s/Ateleport_flag/Cteleport_flag/g s/Ateleport_monster/Dteleport_monster/g s/Ateleport_to/Eteleport_to/g s/wizard_create/Awizard_create/g s/wizard_light/Bwizard_light/g s/generate_cave/Bgenerate_cave/g s/compact_monsters/Acompact_monsters/g s/compact_objects/Bcompact_objects/g s/spell_choice/Aspell_choice/g s/spell_type/Bspell_type/g s/spell_names/Cspell_names/g s/spell_worked/Dspell_worked/g s/spell_order/Espell_order/g s/spell_chance/Fspell_chance/g s/spell_char/Gspell_char/g s/spell_forgotten/Hspell_forgotten/g s/spell_learned/Ispell_learned/g s/spell_worked/Jspell_worked/g s/place_monster/Aplace_monster/g s/place_boundary/Bplace_boundary/g s/place_streamer/Cplace_streamer/g s/place_open_door/Dplace_open_door/g s/place_broken_door/Eplace_broken_door/g s/place_closed_door/Fplace_closed_door/g s/place_locked_door/Gplace_locked_door/g s/place_stuck_door/Hplace_stuck_door/g s/place_secret_door/Iplace_secret_door/g s/place_door/Jplace_door/g s/place_up_stairs/Kplace_up_stairs/g s/place_down_stairs/Lplace_down_stairs/g s/place_stairs/Mplace_stairs/g s/place_gold/Nplace_gold/g s/place_trap/Oplace_trap/g s/place_object/Pplace_object/g s/place_win_monster/Qplace_win_monster/g s/place_rubble/Rplace_rubble/g s/build_type1/Abuild_type1/g s/build_type2/Bbuild_type2/g s/build_type3/Cbuild_type3/g s/version_maj/Aversion_maj/g s/version_min/Bversion_min/g s/rd_shorts/Ard_shorts/g s/wr_shorts/Awr_shorts/g s/purchase_haggle/Bpurchase_haggle/g s/prt_comment1/Aprt_comment1/g s/prt_comment2/Bprt_comment2/g s/prt_comment3/Cprt_comment3/g s/prt_comment4/Dprt_comment4/g s/prt_comment5/Eprt_comment5/g s/prt_comment6/Fprt_comment6/g s/comment1/Acomment1/g s/comment2a/Bcomment2a/g s/comment2b/Ccomment2b/g s/comment3a/Dcomment3a/g s/comment3b/Ecomment3b/g s/comment4a/Fcomment4a/g s/comment4b/Gcomment4b/g s/comment5/Hcomment5/g s/display_char/Adisplay_char/g s/display_scores/Bdisplay_scores/g s/display_commands/Cdisplay_commands/g s/display_inventory/Ddisplay_inventory/g s/display_cost/Edisplay_cost/g s/display_store/Fdisplay_cost/g s/signal_handler/Asignal_handler/g s/new_mana/Anew_mana/g s/Anew_mana_frac/Bnew_mana_frac/g s/find_breakleft/Afind_breakleft/g s/find_breakright/Bfind_breakright/g s/map_diag1/Amap_diag1/g s/map_diag2/Bmap_diag2/g s/You feel Bconfused/You feel confused/g s/appears Bconfused/appears confused/g s/rune of Bprotection/rune of protection/g s/You feel less Bconfused now/You feel less confused now/g s/error in Bmove_cursor_relative/error in move_cursor_relative/g s/You are too Bconfused/You are too confused/g s/You hit a Ateleport trap!/You hit a teleport trap!/g s/You are Bconfused/You are confused/g s/kill weaker Bcreatures/kill weaker creatures/g s/Ateleport short distances/teleport short distances/g s/Ateleport long distances/teleport long distances/g s/Ateleport its prey/teleport its prey/g s/of these Bcreatures/of these creatures/g s/invisible Bcreatures!/invisible creatures!/g s/envelops several Bcreatures!/envelops several creatures!/g s/You are Bconfused/You are confused/g moria-5.6.debian.1/build/0000755000175000017500000000000011074757443013276 5ustar pjbpjbmoria-5.6.debian.1/build/Makefile.deb0000644000175000017500000001250310760060765015463 0ustar pjbpjb# Edited for Debian GNU/Linux. DESTDIR = /home/dgrabiner/moria # DEBIAN NOTE: This file diverges significantly from the original Makefile # for obvious reasons. The original Makefile is Makefile.unix and should # be used on non-Linux systems. # BINDIR is the directory where the moria binary while be put # LIBDIR is where the other files (score, news, hours) will be put # LIBDIR must be the same directory defined in config.h # Edited for Debian GNU/Linux: Next 4 lines are for the FHS # Edited for Debian GNU/Linux: LIBDIR is retired # Edited for Debian GNU/Linux: ETCDIR is where the hours file is kept # Edited for Debian GNU/Linux: LIBSTATICDIR is where help files are kept # Edited for Debian GNU/Linux: LIBVARDIR is where the score file is kept # OWNER is who you want the game to be chown to. # GROUP is who you wnat the game to be chgrp to. BINDIR = $(DESTDIR) ETCDIR = $(DESTDIR)/files LIBSTATICDIR = $(DESTDIR)/usr/lib/games/moria LIBVARDIR = $(DESTDIR)/var/games/moria OWNER = dgrabiner GROUP = dgrabiner # For testing and debugging the program, it is best to use this line. # CFLAGS = -g # For playing the game, you may want to use this line CFLAGS = -O2 # Debian GNU/Linux addition ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS))) CFLAGS += -g endif # For BSD Systems # CURSES = -lcurses -ltermcap # For SYS V Systems CURSES = -lcurses # For XENIX, some XENIX systems may need -ltinfo # CURSES = -ltcap -ltermcap -lx # For AIX systems, compiling in the BSD world; SYS_V must not be defined in # config.h if you use this. #LFLAGS = -lbsd # Normal systems don't require anything here. LFLAGS = CC = cc SRCS = main.c misc1.c misc2.c misc3.c misc4.c store1.c files.c io.c \ create.c desc.c generate.c sets.c dungeon.c creature.c death.c \ eat.c help.c magic.c potions.c prayer.c save.c staffs.c wands.c \ scrolls.c spells.c wizard.c store2.c signals.c moria1.c moria2.c \ moria3.c moria4.c monsters.c treasure.c variable.c rnd.c recall.c \ unix.c player.c tables.c OBJS = main.o misc1.o misc2.o misc3.o misc4.o store1.o files.o io.o \ create.o desc.o generate.o sets.o dungeon.o creature.o death.o \ eat.o help.o magic.o potions.o prayer.o save.o staffs.o wands.o \ scrolls.o spells.o wizard.o store2.o signals.o moria1.o moria2.o \ moria3.o moria4.o monsters.o treasure.o variable.o rnd.o recall.o \ unix.o player.o tables.o LIBSTATICFILES = news origcmds.hlp owizcmds.hlp roglcmds.hlp rwizcmds.hlp \ version.hlp welcome.hlp moria : $(OBJS) $(CC) -o moria $(CFLAGS) $(OBJS) $(CURSES) $(LFLAGS) lintout : $(SRCS) lint $(SRCS) $(CURSES) > lintout lintout2 : $(SRCS) lint -bach $(SRCS) $(CURSES) > lintout TAGS : $(SRCS) ctags -x $(SRCS) > TAGS # you must define BINDIR and LIBDIR before installing # assumes that BINDIR and LIBDIR exist install: chmod 755 $(BINDIR) cp moria $(BINDIR) chown $(OWNER) $(BINDIR)/moria chgrp $(GROUP) $(BINDIR)/moria chmod 2755 $(BINDIR)/moria chmod 755 $(LIBSTATICDIR) # No longer chmod 755 $(LIBVARDIR) (cd files; cp $(LIBSTATICFILES) $(LIBSTATICDIR)) (cd $(LIBSTATICDIR); chmod 444 $(LIBSTATICFILES)) # No longer (cd $(LIBVARDIR); touch scores; chmod 664 scores) # No longer (cd $(LIBVARDIR); chown $(OWNER) . scores; chgrp $(GROUP) . scores) (cd files; cp hours $(ETCDIR)/moria-hours) chmod 644 $(ETCDIR)/moria-hours (cd $(LIBSTATICDIR); chown $(OWNER) $(LIBSTATICFILES)) (cd $(LIBSTATICDIR); chgrp $(GROUP) $(LIBSTATICFILES)) # If you are short on disk space, or aren't interested in debugging moria. # This is handled by dh_strip, so let's not override its' decision. # strip $(BINDIR)/moria clean: rm -r *.o rm -f moria create.o: constant.h types.h externs.h config.h creature.o: constant.h types.h externs.h config.h death.o: constant.h types.h externs.h config.h desc.o: constant.h types.h externs.h config.h dungeon.o: constant.h types.h externs.h config.h eat.o: constant.h types.h externs.h config.h files.o: constant.h types.h externs.h config.h generate.o: constant.h types.h externs.h config.h help.o: constant.h types.h externs.h config.h io.o: constant.h types.h externs.h config.h magic.o: constant.h types.h externs.h config.h main.o: constant.h types.h externs.h config.h misc1.o: constant.h types.h externs.h config.h misc2.o: constant.h types.h externs.h config.h misc3.o: constant.h types.h externs.h config.h misc4.o: constant.h types.h externs.h config.h monsters.o: constant.h types.h config.h moria1.o: constant.h types.h externs.h config.h moria2.o: constant.h types.h externs.h config.h moria3.o: constant.h types.h externs.h config.h moria4.o: constant.h types.h externs.h config.h player.o: constant.h types.h config.h potions.o: constant.h types.h externs.h config.h prayer.o: constant.h types.h externs.h config.h recall.o: constant.h config.h types.h externs.h rnd.o: constant.h types.h save.o: constant.h types.h externs.h config.h scrolls.o: constant.h types.h externs.h config.h sets.o: constant.h config.h signals.o: constant.h types.h externs.h config.h spells.o: constant.h types.h externs.h config.h staffs.o: constant.h types.h externs.h config.h store1.o: constant.h types.h externs.h config.h store2.o: constant.h types.h externs.h config.h tables.o: constant.h types.h config.h treasure.o: constant.h types.h config.h unix.o: constant.h config.h types.h externs.h variable.o: constant.h types.h config.h wands.o: constant.h types.h externs.h config.h wizard.o: constant.h types.h externs.h config.h moria-5.6.debian.1/build/README.debian0000644000175000017500000000216310757653306015401 0ustar pjbpjbmoria for DEBIAN ---------------------- NOTE: Although the package name is "moria" this is actually "umoria 5.5.2", which is the UNIX port of moria. moria is a single player roguelike game that has been around for quite a while, and is the predecessor of variants such as angband. It features scrolling maps, and an infinite (constantly regenerated) dungeon. Moria's dungeons are populated by monsters, some of which are inspired by J.R.R. Tolkien's books. The goal of the game is to find and kill the Balrog, whereupon the player is crowned King. Your player can be created from a combination of 8 races (human, half-elf, elf, halfling, gnome, dwarf, half-orc, half-troll) and 6 classes (warrior, mage, priest, rogue, ranger, paladin), and is measured by 6 attributes (strength, dexterity, intelligence, wisdom, constitution, and charisma). See http://math.la.asu.edu/~grabiner/moria.html for more details about moria, and sites like http://www.mo.himolde.no/~knan/roguelike/index.html or http://www.skoardy.demon.co.uk/rlnews/ for generic roguelike info. Rene Weber , Sat, 14 Oct 2000 10:25:23 -0700 moria-5.6.debian.1/build/changelog0000644000175000017500000006031310757653306015153 0ustar pjbpjb::::::: 1991 :::::::: ---------- 1/4 spells.c: light_area(), always light area immediately next to player even if in a room, could be standing on the edge of a room monsters.c: Grave Wight, no longer has confusion spell, no other wight/wraith has it misc2.c: get_spell(), when enter invalid character, print "You don't know that prayer." instead of "spell" for priests/etc. creature.c: make_attack(), creatures which are repelled should not be confused because they did not hit the player death.c: exit_game(), delete #ifndef TURBOC around the restore_term() call io.c: restore_term(), delete the call to clear() in the MSDOS code, it was trying to use curses after curses had been exited ---------- 1/22 files.c: call pause_line(23) after printing hours file constant.h, config.h: constant.h should always be included before config.h, because some systems redefine constants in config.h rnd.c: include config.h after constant.h main.c, misc2.c, save.c, signals.c: include constants.h before config.h misc2.c, vms/getch.c: new function user_name() for VMS, fix get_name() in misc2.c to call it ------- 1/30 moria2.c: hit_trap(), add msg_print(CNIL) for the trap door case -------- 2/4 io.c: for ATARIST_MWC, use 240 instead of '#' for walls save.c: for ATARIST_MWC, convert 240 to '#' when saving, and '#' to 240 when loading, to avoid conversion problems --------- 2/8 create.c: monval(), cast i to int, otherwise some compilers do the arithmetic with unsigned characters --------- 2/19 makefile: add new macro CURSES, define it for BSD/SYS V/and Xenix config.h: add config info for XENIX, define SYS_V and unix, only undefine register for MSC versions less than 600 (6.00?) creature.c: mon_move, comment out register decl for r_ptr for XENIX systems to avoid a compiler bug misc2.c: place_gold, comment out register decl for t_ptr for XENIX systems to avoid a compiler bug unix.c: ifdef out include of termio.h, for XENIX add include of sys/types.h and define bzero as memset, test for unix or M_XENIX at the top Makefile: add optional commands to install target which chown/chgrp everythin to bin, and put pointer to it at the top ---------- 2/25 util/score: Two new utilities, prscore to print scorefiles, and delscore to delete one entry from a scorefile. config.h: add MORIA_* macros for the Atari ST with GCC death.c, externs.h, io.c, main.c, signals.c, variable.c: Apply Atari ST/GCC patches from Scott Kolodzieski. -------- 3/1 death.c: Amiga must open/close scorefile like MSDOS&VMS io.c: init_curses(),restore_term(), fix bugs in AMIGA code, add code to release resources amiga/*: updated versions of amiga source files, from cg37717@lion.eng.clemson.edu, Corey Gehman atari_st/curscomp: complete rewrite of the curses code by Hildo Biersma store2.c: get_haggle(), do not accept an increment value of zero, turn off increment flag instead of accepting it -------- 3/2 store2.c: store_purchase(), store_prt_gold call was inside `if' now after, did not update gold if store had 13 items and you bought the 13th -------- 3/11 moria1.c: sub3_move_light(), don't print over old location if find_flag is true, unless find_prself is also true, this speeds up movement in find mode by eliminating unnecessary drawing of characters moria2.c: hit_trap(), call move_light() for the teleport trap case, to light up the trap misc1.c, save.c, treasure.c: change ATARIST_MWC ifdefs for using graphic character to ATARI_ST which is true for both MWC and TC io.c: remove all ATARIST_MWC diffs which were needed for the old non-standard curses, change the rest to be ATARI_ST, since both MWC and TC need them -------- 3/14 source/*: add Mac THINK C support mac/dumpres/*: add Mac THINK C support mac/scrnmgr/*: add Mac Think C support moria1.c: find_init(), when !light_flag and !find_prself, must erase the player's '@', because sub3_move_light() won't, see 3/11 change above ------- 3/15 mac/*: add Mac THINK C support *: put file name and 1991 copyrights in all source files ------- 3/23 save.c: prevent resurrection of a total winner character constants.h, creature.c, monsters.c, recall.c: add new flag CM_ONLY_MAGIC, set this flag in creature.c, check the flag in recall.c, allows recall to print movement speed for Quylthulgs creature.c: when a wand is drained of charges, inscribe it as {empty} if it is not known2 -------- 3/24 files.c, ibmpc/ms_misc.c: ifdefed out msdos_intro(), since that routine is obsolete now doc/moria.6: add -S option to list at the top ibmpc/CONFIG.DOC: update for Umoria 5.x, remove kneller's address, and put in my address ------- 3/25 config.h, constant.h, */*.c: move VMS definition for ESCAPE from config.h to constant.h, now all files include config.h before constant.h *: linted all sources files, changed version numbers to 5.3 ------- 3/30 vms/*, ibmpc/ms_misc.c, config.h, death.c, dungeon.c, externs.h, files.c, io.c, save.c: merge in changes from Ralph Waters, which are needed to compile the sources under VMS and IBM-PC/Turbo C. moria2.c, store2.c, *.c: get_item(), show_inven() take new parameter mask, if mask is non-zero, they only list items indicated by mask array, store_sell() calculates a mask based on what store will buy store2.c: purchase_haggle(), sell_haggle(), if the auto increment is larger than the difference between the store's offer and the player's offer, then set the auto increment to the exact difference dungeon.c, externs.h, moria1.c, moria2.c, variable.c: eliminate search_flag, it was redundant, replace all uses with (py.flags.status & PY_SEARCH) tables.c: remove good armor items from armory, to force players to search for them in the dungeons, hard leather boots, iron helm, partial plate, full plate misc1.c: alloc_monster(), always create dragons sleeping here, to give the player a sporting chance moria1.c: inven_command(), when pack not empty and show_weights flag true, display capacity along with weigth carried on first line of inventory spells.c: build_wall(), permanently light walls created within range of player's lamp spells.c: earthquake(), fix it to act just like build_wall when a monster is trapped in a wall creature.c, externs.h: movement_rate(), now static *: release 5.3.1 sources ------- 4/27 ms_misc.c, externs.h: change declarations of warn() to match definition, change declaration and definition of error() to match warn(), externs.h: fix declarations for sleep(), find_init(), show_inven(), get_item() death.c: display_scores(), don't set player_uid for non UNIX/VMS system duplicate_character(), ifdef out code which is unreachable for non UNIX/VMS system, make all returns have a value sets.c: set_null(), add a #pragma argused for TURBO C ms_misc.c: fix three lines that had an assignment inside an if externs.h: add prototypes/declarations for VMS files getch.c and uexit.c moria1.c: see_wall(), change ATARIST_MWC ifdef to ATARI_ST atari_st/curscomp/curses.c: winsch(), first loop ran in wrong direction externs.h: add declarations for atari st functions atari_st/moria.prj: new file, TC project file for Umoria death.c: highscores (), change fseed to fseek, typing error creature.c, death.c, desc.c, dungeon.c, files.c, io.c, moria1.c, moria2.c, store2.c, wizard.c, atarist.c: include stdlib.h if ATARIST_TC to get prototypes for standard library functions generate.c: for ATARIST_TC, include atarist/curscomp/curses.h: change mvadd* macros from compound statements to conditional expressions, so that all returns values are error checked io.c: for ATARIST_TC, include ext.h to properly define (?) sleep config.h: for ATARIST_TC, define index strchr save.c: sv_write()/get_char(), define t_ptr for both MSDOS and ATARI_ST; get_char(), change ATARIST_MWC ifdef around chmod call to ATARI_ST include time.h for ATARIST_TC unix/Makefile: change ONWER to OWNER creature.c: creatures(), give moves to monsters trapped in rock, so that they will die/dig out immediately, mon_move() if a monster in rock is already dead, don't kill it again *: update address info in all files io.c: change __GNU_C_ to __GNUC__ config.h: the test for undefining 'register' was wrong, it was undefing it for all non-MSC compilers moria2.c: tunnel(), heavy weapon code wrong, eliminate >>2 of penalty, add penalty instead of subtracting it help.c: ident_char(), add period after Giant Frog. monsters.c: novice priest, change sleep from 10 to 5 to match other novice 'p' moria1.c, store2.c, *.c: get_item() new parameter 'message', when invalid letter hit, print this message if non-zero instead of beeping, store_sell() pass message "I do not buy such items.", fix all other callers to pass CNIL -------- 4/28 misc2.c, files.c: put_misc2(), file_character(), when player at max level, don't print a number for Exp to Adv, instead print ****** io.c: msg_print(), put multiple messages on the same line if they are short enough ------- 5/22 externs.h: ifdef out declaration of sprintf for NeXT io.c (init_curses): correct atarist/GNUC code for signal call, ifdef was wrong ------- 7/6 spells.c (unlight_area): Unlight all floor spaces with `lr' set, instead of just the room floors spaces. This darkens the doorways. moria1.c (light_room): Add code to set the fm flag, necessary so that the above fix does not unlight doors that it shouldn't. io.c (msg_print): Don't combine NULL messages with other messages. save.c (get_char): Use msg_print when printing the `departed spirit' message. -------- 7/26 store2.c (purchase_haggle, sell_haggle): If the automatic increment plus the last offer passes the shop keepers current ask, then clear the incr. -------- 10/5 *: Add changes needed to prevent warnings from the IBM-PC TURBO C compiler. misc[1234].c, moria[1234].c: misc[12].c and moria[12].c were each split into two files, because they were too large for TURBO C's integrated environment *: adjust all makefiles, externs.h, etc to account for new moria/misc files TCCONFIG.TCU, TCPICK.TCU: new files, uuencoded copies of Turbo C setup files config.h, ms_misc.c: New define USING_TCIO, used to prevent including curses.h in ms_misc.c. Defaults to defined if using TURBOC on an IBM-PC. io.c: delete special purpose AMIGA code, it now uses curses amiga/amiga.h: Deleted. amiga/amiga.c: Delete all curses stubs. -------- 10/6 macrsrc.h: change type of resType, ResID to long macrsrc.c: eliminated search_flag from macrsrc.c (see 3/30 changes) config.h: put back switches RSRC, RSRC_PART1 and RSRC_PART2 ScrnMgr.ro: changed def of MBAR #228 (fixes crash on Mac Plus) and INFO #1 (Make default window be full screen) ScrnMgr.c: check for reconfig flag enabled for THINK_C, add recognition of MacClassic (and LC?) keyboard, now assumes unknown keyboard type has control key, other misc cleanups moria.ro: changes version string macconf.c: config.h included for consistency mac.c: added support for 8-column tabs mac/Install.doc: new file, installation instructions for THINK C macconf.c, machelp.c, macscore.c scrnmgr.c: covered up error in THINK C includes files OK/Cancel for ok/cancel death.c, save.c: delete setmode calls for IBM-PC, instead open files in binary mode --------- 10/12 *: Changed version number to 5.4. save.c: change code to accept savefiles with version numbers greater than the version number of the game, savefile format frozen as of 5.2.2 externs.h: ifdef out the troublesome sprintf declaration config.h: force `unix' to be defined for unix systems, since some stupid systems (e.g. AIX) don't already define it --------- 10/15 externs.h, moria4.c, ms_misc.c: correct typos discovered under MSDOS --------- 10/19 spells.doc, exp.doc: New documentation files. --------- 10/26 vms/uexit.c, externs.h, io.c, signals.c: Define uexit as void, and ifdef out exit declarations when VMS. vms/moria.opt: add misc[34].obj and moria[34].obj ibmpc/ms_misc.c: correct typo in error() pr_items.c, pr_monst.c: main now returns 0 CONFIG.DOC, TERMCAP, ms_ansi.c: use le/do instead of obsolete bc/xd dragon.inf: moved from util/weapons to doc, and updated it to be accurate spoilers: Update from USENET FAQ posting. --------- 11/17 io.c: ifdef out code checking for 8 char TABS, because it assumes that the screen is exactly 80 characters wide moria[12].[ms/txt]: Correct a few typos. *: Fix all file permissions. ::::::: 1992 :::::::: Maintenance taken over by David Grabiner --------- 7/16 moria4.c: bash(), use random direction if player is confused spells.c: fire_ball(), fire_bolt(), don't update recall if monster not lit; this can happen if bolt hits an invisible monster spells.c: speed_monsters(), sleep_monsters2(), dispel_creature(), turn_undead(), only affect creatures within MAX_SIGHT spells.c: mass_poly(), area of effect should be <= MAX_SIGHT, was < spells.c: destroy_area(), remove light from player's spot spells.c: enchant(), add new variable limit, chance of failure is now (plusses/limit), with very slight chance of success over limit scrolls.c: when enchanting melee weapons to damage, set limit to weapon's maximum damage, otherwise use 10 to give behavior similar to old method misc2.c: magic_treasure(), make standard deviation of damage bonus on a melee weapon proportional to weapon's maximum damage; these changes mean that daggers can no longer become powerful weapons treasure.c: the Zweihander has now become a great weapon, value increased from 1000 to 1500 externs.h: fix declaration for enchant() staffs.c, wands.c: give everyone a slight chance to use difficult wands and staffs, otherwise a warrior will never be able to use many items --------- 7/23 death.c: print_tomb(), insert msg_print(CNIL) so that "You are using:" and "You are carrying:" don't get combined as one message; this made it impossible to see the equipment list store2.c: haggle_insults(), insert msg_print(CNIL) so that insult is always recognizable store2.c: purchase_haggle() and sell_haggle(), new variable didnt_haggle, don't call updatebargain if no haggle store1.c: noneedtobargain(), changed to sliding scale, (good-3*bad) must be more than 5 + (price/50) to skip haggling, so that haggling for cheap items is over quickly, but can still eventually skip haggle for all items store1.c: updatebargain(), now update for all items worth >9 gold, instead of just 10-999, since it is now possible to skip haggling for more valuable items as well --------- 7/25 moria4.c: bash(), unsuccessful bash takes a turn; otherwise, you can attempt to bash in different directions while confused or to locate invisible monsters; eliminate variable no_bash --------- 7/27 check all above changes moria4.c: bash(), get "You bash at empty space" method when bashing a wall, corrected to "nothing interesting happens"; this also prevents bashing from locating a secret door --------- 8/9 merge in all changes from 5.4.0 to 5.4.1 creature.c: update attack information only if monster is visible; update death information even if monster is not visible, since information will be on tombstone *: change version number to 5.5.0 --------- 8/12 spells.c: enchant(), guard against randint(0) if called with limit of 0 (it shouldn't be). moria4.c: throw_object(), py_bash(), don't do negative damage shortnam.sed, spells.c: fire_ball(), fix spelling of "envelops" doc/faq: remove old spoilers file, and put current FAQ here instead *: put my name (DJG) in credits as contact *: change copyright date in all source files to 1992 ---------- 8/13 release umoria 5.5.0 ---------- 10/26 doc/moria[12].[ms,txt]: correct some typos, and make changes for 5.5.0 ---------- 10/31 misc4.c: scribe_object() allowed inscriptions longer than 12 characters if 13-24 characters availble for inscription, could overwrite other data ::::::: 1994 :::::::: ---------- 6/6 scrolls.c: aggravate monster should give "humming noise" before "stirring" scrolls.c: always identify scrolls which print a message unix/unix.c: change from obsolete getpw() to getpwuid() to get UID death.c: #include seems to be needed on XENIX and SYSV death.c: fix #ifdef (...) || defined(...) save.c: set fd=-1 after closing file to prevent double close dungeon.c: move hero/superhero to first status check so that player's HP won't go below 0 in mid-turn (killing him) and then become positive doc/moria[12].ms: fixes so that file works with groff store1.c: sell_price(), check for consistent sale prices compared pointers rather than values create.c: get_all_stats(), set player level to 1 before calling set_use_stat with constitution (which used level to check hit points) misc3.c: misspelled variable "holderr" in MWC-specific code misc3.c: prt_experience(), put check against max level in while loop so that level gain is never tested if player is max level misc3.c: gain_level(), corrected comment for loss of extra experience when player gains multiple levels moria3.c: monster_death(), don't make player a winner if already dead store2.c: get_haggle(), %d should be %ld misc3.c: todis_adj(), case of dexterity 3 was omitted spells.c: wall_to_mud(), may find objects in rubble as with tunneling ---------- 6/7 io.c, signals.c: included changes from Andrew Chernov for 386BSD support io.c, config.h: included changes from Berthold Gunreben for HP-UX support config.h, death.c, files.c: added patches for HP Apollo, which doesn't allow multiple processes to use the same file config.h: defined MORIA_LIB to contain pathname for moria/files, to simplify configuration moria1.c: inven_command(), get_item(), added code from Harry Johnston which allows use of 0-9 to specify an item with the corresponding inscription doc/moria[12].ms: documented above change files/version.hlp: my name appeared both as author and "other contributor" scrolls.c: set AC bonus on cursed weapon, hit/dam bonuses on cursed armor to zero (in case HA/DF/gauntlets of slaying had bonus) creature.c: don't print message when invisible monsters recover from bash creature.c, moria3.c, spells.c: reworked monster confusion, monster's confused value now gives duration, turn_undead has guaranteed duration equal to player's level, other confusion random creature.c: undead which have been turned will flee rather than moving randomly, attack only if cornered recall.c: print "It is resistant to" if monster has not cast any spells but breath flag is known (because monster resisted an attack) monsters.c: allow monsters to resist attacks if they have no breath weapon but use the attack type (so fire giants resist fire) sets.c: new function set_large(), identifies objects too large to fit in a chest or be carried by small creatures misc3.c: get_obj_num(), new parameter must_be_small to generate only small objects when appropriate; place_object() passes it files.c: random object sample passes must_be_small constant.h, treasure.c, monsters.c, moria3.c, recall.c: new constant CM_SMALL_OBJ for chests, and for monsters carrying only small objects, check it in monster_death() by setting a bit in treasure type, allow it to be recalled moria3.c: summon_object(), object must be small if bit flagged above many: change all other calls to place_object to set must_be_small to FALSE externs.h: fix declaration of get_obj_num(), place_object(), add set_large() store1.c: noneedtobargain(), change scale again, (good-3*bad-5) must be positive and its square must be at least price/50, this allows high-level characters to become good bargainers for expensive items ---------- 6/8 lint all above changes, fix assorted typos recall.c: recalled spell frequency for non-spellcasters in wizard mode monsters.c: checked small objects/resistances for consistency, fixed error creature.c: creatures given resistance by setting of breath bits tried to cast spell, calling randint(0) moria3.c: error in testing type caused all monsters which should drop both objects and gold to drop only gold creature.c: turned undead must call get_moves so they know which way to flee ---------- 6/9 moria1.c: inven_command(), get_item(), print 0-9 in prompt message when appropriate moria[12].ms: clarified that digit inscriptions work only on items in pack prayer.c: strengthened Holy Word player.c: reduced failure chance for Holy Word check all changes, fixed more typos ---------- 6/10 moria1.c: inven_command(), get_item(), 0-9 was printed in wrong place ---------- 6/22 spells.c: td_destroy(), td_destroy2(), don't disarm/unlock chests that are already empty treasure.c: up staircase had extra space after name doc/moria[12].ms: proofread, fix many typos ---------- 6/25 monsters.c: allow thieves to pick up objects on the floor main.c,config.h,amiga/amiga.c,amiga/timer.c: included changes from Ronald Cook for Lattice C support on Amiga death.c,io.c,signals.c,unix.c,config.h: included changes from Brian Johnson for Linux support changed version number to 5.5.1 fix more lint errors util/mergemem: code from Eric Bazin to merge monster memories *: changed all copyright dates to 1994 released version 5.5.1 ---------- 7/5 death.c: || !defined(APOLLO) should be && ---------- 7/11 store2.c: get_haggle, changed %ld back to %d since variable is 16 bits ---------- 7/20 treasure.c: fixed many inconsistencies, mostly prices and names misc2.c: magic_treasure(), fixed values of SU and SA, which weren't changed when see invisible was moved from SA to SU; also changed magical bonuses for these weapons store2.c: increase_insults(), don't clear out haggling record if player is thrown out (it might be worse than zero), just penalize as for bad bargain ---------- 7/21 treasure.c: fixed a few more inconsistencies with items files.c, misc32.c: file_character(), put_misc2(), don't print "Exp to Adv" if over max_level (i.e., winner) files.c: file_character(), leave enough space for printing 8-digit experience points misc3.c: put_misc2(), make display consistent with above change misc3.c: new function prt_8lnum(), print a long variable in 8 digits of space, needed by revised put_misc2() above death.c: need flock hack for HPUX io.c: #include for HPUX was inside #if 0 ibmpc/*: fix several typos in PC-specific files, also one in config.h changed version to 5.5.2 released version 5.5.2 moria (5.5.2-5) unstable; urgency=low * Changed location of score file from /var/lib/games/moria/scores to /var/games/moria/scores per FHS. (Closes: #115849) * Fixed handling of score file on upgrades (do not null it out!). * Applied fixes to a few buffer overflows. (Thanks to Lars Helgeland for noticing the overflows and supplying the patches.) (Closes: #115745) * Upgraded policy to version 3.5.6.0. -- Rene Weber Wed, 24 Oct 2001 22:44:05 -0400 moria (5.5.2-4) unstable; urgency=low * Fixed dependencies (was compiled against libncurses4, what was I doing that day?). * Corrected explanation of the 'V' command in moria2.txt (but not in the nroff source for that documentation). * Removed use of dh_suidregister. -- Rene Weber Mon, 9 Jul 2001 23:31:01 -0400 moria (5.5.2-3) unstable; urgency=low * Added a Build-Depends line. * Changed the handling of the build directory for the convenience of porters (should have no impact on users). * Changed short description so that it does not include the name of the package. * Corrected path to /usr/games/moria binary in the menu. Closes: #81353 -- Rene Weber Sat, 6 Jan 2001 02:47:02 -0700 moria (5.5.2-2) unstable; urgency=low * Fixed typos in the control/README.debian file * Updated the author's e-mail address in the copyright file * Updated the author's web page listed in the README.debian * Installed a new version of the FAQ (reflecting the author's move) -- Rene Weber Sat, 14 Oct 2000 10:23:48 -0700 moria (5.5.2-1) unstable; urgency=low * Initial Release. * Added DEBIAN_LINUX #define to handle code customizations. * Needed to include termios.h in io.c * All instances of signal() changed to sysv_signal() since libc6 defaults to BSD semantics. * Instead of redefining getuid, just ifdeffed it out of unix.c * Changed LOCK_EX and LOCK_SH definitions in death.c (to avoid redefinition warnings). * Library files are in /usr/lib/games/moria except for the scores file which is in /var/lib/games/moria and the hours file which has been renamed to /etc/moria-hours * Makefile changed to make the binary setgid instead of setuid, as required by Debian Policy 5.10. None of the code itself needed to be touched, since it already relinquished uid and gid in the original code. * Saved game file is named ".moria-save" not "moria-save" -- Rene Weber Sun, 28 May 2000 16:35:38 -0400 moria-5.6.debian.1/build/postrm0000644000175000017500000000040710757653306014546 0ustar pjbpjb#!/bin/sh -e # Shamelessly stolen from Joey Hess' bsdgames-2.12-9 SCOREFILES=" /var/games/moria/scores" # Remove high score files on purge. if [ "$1" = "purge" ]; then rm -f $SCOREFILES rmdir /var/games/moria /var/games 2>/dev/null || true fi #DEBHELPER# moria-5.6.debian.1/build/conffiles0000644000175000017500000000002110757653306015162 0ustar pjbpjb/etc/moria-hours moria-5.6.debian.1/build/Makefile0000644000175000017500000000455110757653306014743 0ustar pjbpjb# DEBIAN NOTE: This file is (obviously) just a simple stub. It did not # exist in any form in the original. # The below can be customized for taste. builddir = build make = make # This target forwards the make to the build directory (unless it is one of # those below, of course) .DEFAULT moria: @if ( test \! -d $(builddir) ) then $(make) builddir; fi @echo "*** Entering $(builddir)/ to actually make the package." ( cd $(builddir) && $(make) $@ || exit 1 ) # This target is used to avoid complaints from dpkg-source, use with caution! # See README.debian-build for details. clean: if ( test -d $(builddir) ) then rm -r $(builddir); fi # To forward clean requests to the build directory (not actually used by my # package at this point. buildclean: @if ( test -d $(builddir) ) then \ ( cd $(builddir) && $(make) clean || exit 1 ) \ fi # This target tests if the build directory exists, and complains if it does. # It is called from debian/rules, and is placed in this makefile simply so # it can inherit the builddir variable. isclean: @if ( test -d $(builddir) ) then \ echo -e "\nERROR: You must remove the $(builddir) directory before using dpkg-buildpackage";\ echo " due to limitations in dpkg-source. "\""make clean"\"" from the base dir"; \ echo -e " will do this for you. See README.debian-build for details.\n";\ exit 1; \ fi # This target actually makes the build directory and populates it with the # required symlinks. It also makes WARNING files so that people who haven't # read README.debian-build hopefully will not modify files in this directory. builddir: @ echo "*** Making $(builddir)/ which will contain symlinks to the sources..." mkdir $(builddir) || exit 1 chmod 700 $(builddir) || exit 1 ( cd $(builddir) && ln -si ../files ../unix/* ../source/* . || exit 1 ) ( cd $(builddir) && echo -e "WARNING: Do not modify anything in this directory; it may be purged without\nwarning. If you want to change the source do it in the source/ or unix/ dirs\nto which these symlinks point. See README.debian-build for details." >> zz-WARNING && cp -ip zz-WARNING 00-WARNING && cp -ip ../debian/README.debian-build . || exit 1 ) @ echo "*** Done making $(builddir)/" @ echo moria-5.6.debian.1/build/rules0000644000175000017500000000332510757653306014356 0ustar pjbpjb#!/usr/bin/make -f # MAde with the aid of dh_make, by Craig Small # Sample debian/rules that uses debhelper. GNU copyright 1997 by Joey Hess. # Some lines taken from debmake, by Cristoph Lameter. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 build: build-stamp build-stamp: dh_testdir # Add here commands to compile the package. ( cd build ; $(MAKE) ) touch build-stamp clean: dh_testdir dh_testroot rm -f build-stamp install-stamp # This make isclean is to make sure the build directory does not # exist, as dpkg-source cannot handle it. See README.debian-build. make isclean # Add here commands to clean up after the build process. dh_clean install: install-stamp install-stamp: build-stamp dh_testdir dh_testroot dh_clean -k dh_installdirs # Add here commands to install the package into debian/tmp. ( cd build ; $(MAKE) install DESTDIR=`pwd`/../debian/tmp ) touch install-stamp # Build architecture-independent files here. binary-indep: build install # We have nothing to do by default. # Build architecture-dependent files here. binary-arch: build install # dh_testversion dh_testdir dh_testroot dh_installdocs dh_installexamples dh_installmenu # dh_installemacsen # dh_installinit dh_installcron dh_installmanpages # dh_undocumented dh_installchangelogs dh_strip dh_compress dh_fixperms --exclude=usr/games/moria --exclude=var/games/moria # dh_suidregister dh_installdeb dh_shlibdeps dh_gencontrol # dh_makeshlibs dh_md5sums dh_builddeb source diff: @echo >&2 'source and diff are obsolete - use dpkg-source -b'; false binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary moria-5.6.debian.1/build/postinst0000644000175000017500000000036610757653306015111 0ustar pjbpjb#!/bin/sh -e SCOREFILES=" /var/games/moria/scores" # If the score file is not extant, touch it into existence. for file in $SCOREFILES; do if [ ! -e $file ]; then touch $file chown root.games $file chmod 664 $file fi done #DEBHELPER# moria-5.6.debian.1/build/README.debian-build0000644000175000017500000000404310757653306016475 0ustar pjbpjbmoria for DEBIAN ---------------------- *** THE BUILD DIRECTORY IS SUBJECT TO BEING DELETED WHEN MORIA IS BUILT *** NOTE: Although the package name is "moria" this is actually "umoria 5.5.2", which is the UNIX port of moria. SPECIAL NOTE FOR PEOPLE WORKING WITH THE SOURCE Do NOT change anything in the moria-5.5.2/build directory (if it exists for you). Read on for rationale. Due to the fact that upstream uses a somewhat unusual method of having the user make symbolic links depending on what operating system they are building, there is a significant oddity to how it is built for Debian. The main issue is that dpkg-source, one of the tools for building Debian packages (and which is called by dpkg-buildpackage) cannot handle the appearance of symbolic links; however, the autobuilders require that the links either be present or automatically generated. The compromise I have made is that I have written a stub Makefile in the main moria directory, which creates a "build" directory (called "build/" by default, although customizable in that Makefile) and populates it with the required symlinks. This satisfies the requirements for autobuilders, except that the build directory persists after the build is complete so a "rebuild" will fail with dpkg-source complaining that there are unrepresentable changes in the build directory. To get around this, I have made a "clean" target in my stub makefile which will "rm -f build/", and placed a check in debian/rules that exits with an error (and instructions to run make clean) if the build directory exists. The practical upshot of this is that anything in moria-5.5.2/build (where "build" is the build directory as defined in moria-5.5.2/Makefile) is subject to (almost) automatic deletion. If you are modifying the source, do NOT do it in the build directory, but rather do it in the src/ and unix/ directories to which the symlinks point. *** THE BUILD DIRECTORY IS SUBJECT TO BEING DELETED WHEN MORIA IS BUILT *** Rene Weber , Sun, 12 Nov 2000 12:50:32 -0500 moria-5.6.debian.1/build/faq.20010000644000175000017500000007603110757653306014360 0ustar pjbpjbPath: senator-bedfellow.mit.edu!bloom-beacon.mit.edu!howland.erols.net!newshub2.home.com!news.home.com!news1.rdc1.md.home.com.POSTED!not-for-mail Sender: grabiner@CC664387-B Newsgroups: rec.games.roguelike.moria Subject: rec.games.roguelike.moria Frequently Asked Questions Expires: 22 Oct 2001 00:00:00 GMT From: grabiner@alumni.princeton.edu (David J. Grabiner) Message-ID: Lines: 773 X-Newsreader: Gnus v5.7/Emacs 20.5 Date: Sun, 21 Oct 2001 22:12:03 GMT NNTP-Posting-Host: 24.249.239.64 X-Complaints-To: abuse@home.net X-Trace: news1.rdc1.md.home.com 1003702323 24.249.239.64 (Sun, 21 Oct 2001 15:12:03 PDT) NNTP-Posting-Date: Sun, 21 Oct 2001 15:12:03 PDT Organization: Excite@Home - The Leader in Broadband http://home.com/faster Xref: senator-bedfellow.mit.edu rec.games.roguelike.moria:7340 Frequently Asked Questions for rec.games.roguelike.moria Last changes: 8/7/01 (Palm port, changed my address) 6/15/01 (new mirror) 5/12/01 (moved Australian mirror) First, a general guideline for posters. When you post any question related to playing or debugging the game, please give the version number, which you can get during the game by pressing "v". These are the questions in the Moria Frequently Asked Questions list. Quick answers to some questions are given in parentheses; more detailed answers to those questions with numbers are in the list which follows. The answers below are separated by form feeds, so that in most news readers, you can get the answer you want without looking at the rest of the spoilers. (Search for the string "Q5", for example.) Many of the answers are only correct for Umoria versions (4.87 and 5.x); I don't know much about the other versions of Moria. Please send any corrections or other suggested questions to me at grabiner@alumni.princeton.edu The FAQ is now maintained on the Web at A copy of the FAQ as it was last posted may be obtained by FTP from the RTFM archive, ftp://rtfm.mit.edu/pub/usenet/rec.games.roguelike.moria/rec.games.roguelike.moria_Frequently_Asked_Questions or by using the mailserver on RTFM. To use the mailserver, send a message to mail-server@rtfm.mit.edu containing the line "send /pub/usenet/rec.games.roguelike.moria/rec.games.roguelike.moria_Frequently_Asked_Questions" There is also a WWW page for Moria, with links to the spoilers, newsgroup, this FAQ, and the FTP site. It is The most common questions, asked by both beginners and others: Q1. How do I get the Moria sources/executables/documentation? (PC executables are available at Linux source is available at . sources and other exeuctables are on the main archive at .) Q2. I can't get Moria/Angband set up on my machine; is there a server on another machine that I can use? (Yes; telnet://chungkuo.org) What does this item do? (Answer is below with the spoilers.) Why do most winning characters carry several copies of spell books? (In case one gets stolen.) What does the (-2) in Chain Mail (-2) [14,+2] mean? (It's a penalty to hit, caused by the heavy armor.) Q3. How do I use wizard mode, and what can I do in it? (In 5.x, just type control-W.) Non-spoiler questions: Q4. How does resistance work? Are two items of resistance cumulative? (Not if both are worn items.) Q5. How does speed work? Do you get faster if you are already Very Fast and get another speed item? (Yes.) Q6. I'm playing Moria version V; how does that compare to the current version? Is it compatible? Q7. I think I've found a bug; what should I do? (Check that it isn't already known, then report it with the version number and system.) Common spoiler requests: Q8. What are the special abilities of ego weapons? Crowns? Amulet of the Magi? Cloak of Protection? Q9. How much damage do spells and wands do? Q10. What does spell Y do? Q11. On what level do you find X? (Level 25 is best for gain stat potions.) Q12. How many attacks can I get with this weapon? Q13. How do you kill an ancient multi-hued dragon? (Usually, you don't.) Q14. How do you kill an emperor lich? (With speed and spells.) Q15. What is the grape jelly trick? Does it work in Umoria 5.x? (No.) Questions related to the source code: Q16. I don't like haggling; can I change the source code to turn it off? Q17. How do you create objects in wizard mode? Q1. How do I get the Moria sources/executables/documentation? A working version of Moria 5.5.2 is now available for the PC; it's also available at the main Moria archive, but this URL is more likely to work. http://www3.ns.sympatico.ca/dmswaine/m552-386.zip Linux sources (designed for Debian, but they also work on Red Hat at least) are at http://packages.debian.org/moria Umoria 5.5.2 has been ported to the PalmOS at http://roguelike-palm.sourceforge.net/kMoria/index.php The main Moria archive has moved to a new home; it makes files available by anoymous FTP: ftp://ftp.greyhelm.com/pub/Games/Moria Three near-complete mirrors are available. ftp://ftp.funet.fi/pub/unix/games/moria/ ftp://ftp.planetmirror.com/pub/roguelike/moria/ (in Australia) (The third is a slow connection; please do not use it if you can get to another site.) http://www.piratehaven.org/~beej/moria/mirror/Games/Moria/ Use the pathnames listed below, ignoring the leading /pub/Games/Moria. Some files on the mirrors may be compressed with different compression programs such as gzip. The documentation, including the official manual and this FAQ, is available at http://www2.ecst.csuchico.edu/~beej/moria/ The sources for Umoria 5.5.0 were also posted to comp.sources.games, so they should be available (in compressed shar form) on any site which archives comp.sources.games, such as ftp.uu.net. The following paths give the structure of the Moria archive; they will probably be maintained when the archive moves somewhere else. /pub/Games/Moria/[machine name] Executables for the Amiga, Atari ST, IBM PC, and Mac; look at the README files in these directories for more information. Some of these files may need to be transferred in binary mode; type "binary" before transferring the files. KSU has both color and monochrome executables for the IBM PC. European users can also get Mac binaries from jyu.fi, in a file /maclib/game/moria.sit.bin. /pub/Games/Moria/pc/80386-5.5.2/m552-386.zip This is the 5.5.2 executable for the PC. /pub/Games/Moria/source/um5.5.2.tar.Z A compressed tar file containing the entire source, for use on any system; if you have tar on your system, this is probably the file that you want. (If you don't have compress, you can FTP it as well; it is /pub/Games/Moria/compress.tar.) This file must be transferred in binary mode; type "binary" before getting the file. Once you have the tar.Z file, type "zcat um5.5.2.tar.Z | tar xf -" to extract the files, and read the README files for help in installing. /pub/Games/Moria/pc/zip-arc/mor55src.zip A ZIP file containing the source. /pub/Games/Moria/pc/zip-arc/wmoria10.zip_exec /pub/Games/Moria/pc/zip-arc/wmoria10.zip_source Source and Modula-2 executables for Wmoria 1.0, a port of Umoria 5.5.0 to Windows 3.1. /pub/Games/Moria/patches Patches for upgrading Moria from one version the the next version, and for modifications. /pub/Games/Moria/XMoria/xm1.07.tar.Z The source to Moria for X Windows. /pub/Games/Moria/doc The documentation for Moria 5.5, including the official documentation, the FAQ file, and a complete monster list. /pub/Games/Moria/pc/mono5.5 The auxilliary files are in this directory; you may need them if you have an executable without them. /pub/Games/Angband The source to Angband for UNIX, and source and executable for the PC and Mac. /pub/Games/Moria/boss The source distribution, in Pascal, for BOSS. /pub/Games/Moria/vms The source discribution, in Pascal, for VMS Moria 4.8 and 5.0. Umoria 5.x will also work on VMS machines. (Note that VMS Moria 5.0 is not a version of Umoria 5.x.) /pub/Games/Moria/unofficial Other unofficial modifications of Moria, including JAMoria, the druid version for the PC, and the sources for Morgul and Pmoria. /pub/Games/Moria/utils/calchits.shar.Z A program for calculating the average damage done with various weapons, allowing you to compare them. VMS sources for Imoria are available on ubvms.cc.buffalo.edu, in a directory /maslib/games/imoria. VMS Moria 4.8 and 5.0 sources are also there. Linux code for Imoria is available from http://members.xoom.com/kertes/index.htm Q2. I can't get Moria/Angband set up on my machine; is there a server on another machine that I can use? (Yes; telnet://chungkuo.org) There is a BBS at telnet://chungkuo.org which has Moria and many other Roguelike games. Telnet to this site, or see the Web page http://chungkuo.50megs.com/gnet.html for more information. Note that the standard telnet client in Windows is buggy, and will cause problems with this BBS. The maintainer of the BBS recommends Mtelnet and makes it available on the Web page. Q3. How do I use wizard mode, and what can I do in it? In Umoria 5.x, anyone can use wizard mode by typing ^W. However, characters who play in wizard mode are permanently barred from the scoreboard; wizard mode should be used only for debugging and experimenting. In 4.87 on Unix systems, only the person who installed the game can use wizard mode; if you are the installer, the passwords are in the source file constants.h. In PC-Moria 4.8x, you need to know the passwords to use wizard mode, and the password will depend on who compiled your game. 4.87 has both wizard and god modes; 5.x's wizard mode is equivalent to the old god mode. The 4.87 wizard mode allows you to do only things related to the game (cure all problems, teleport, identify). The 5.x wizard mode and 4.87 god mode allow you to test the program by editing your character, creating objects, deleting monsters, and similar things. In wizard mode, ^H or DELETE will give you a list of the available commands. Q4. How does resistance work? Are two items of resistance cumulative? Resist heat/cold potions and spells give temporary resistance to heat or cold. All other resistance items give permanent resistance. Two permanent resistances are not cumulative, and two temporary resistances are cumulative only in duration. Fire and cold do 1/3 damage if you have single resistance, 1/9 if you have double. Acid does 1/2 damage if you have any armor to corrode, 1/3 if you have resistance but no armor, and 1/4 if you have resistance and armor. Lightning does 1/3 damage if you have resistance. There is no resistance against poison gas. Q5. How does speed work? Do you get faster if you are already Very Fast and get another speed item? Very Fast is the highest speed that can be displayed, but if you are fortunate enough to find several speed items, you can get still faster. Permanent speed items (rings and boots) are cumulative, and temporary speed (potions, spells, and staffs) can add one more point to your speed. Multiple uses of temporary speed are cumulative only in duration. Q6. I'm playing Moria version V; how does that compare to the current version? Is it compatible? Moria versions: Umoria 5.5.2: This is the current version of Umoria. It will accept characters from all Umoria 5.x versions. Umoria 5.3.0-5.5.1: These are essentially identical to 5.5.2, and compatible with it, although 5.5.2 fixes a few bugs, and there have been a few minor changes. Upgrading from 5.5.1 to 5.5.2 is probably not necessary; upgrading from earlier versions is recommended. Umoria 5.2.2: This is in good condition, and compatible with the current version. One bug: don't rest more than 10,000 turns in place, and leave the level if you start seeing lots of "Compacting monsters..." messages, or the game may lock up. Umoria 5.2.1: This is playable, but has no high scores file; you probably want to upgrade if possible. Umoria 5.1.0-5.2.0: These versions can be played, but are somewhat buggy. If you run into an invisible, invincible monster which doesn't move or attack, get off the level. If you can FTP the sources or executables, you should upgrade. The U is often omitted from the names of the following Umoria versions. Umoria 4.87/PC-Moria 4.87x: This version is based on the old VMS Moria. It is relatively bug-free, but it doesn't have the features of the 5.x versions, such as monster memory. The save file format is incompatible with 5.x, and several people have failed in attempts to write a conversion program. Umoria 4.85: A moderately buggy version, also based on VMS Moria. Umoria/PC-Moria 4.83: An extremely buggy version, based on VMS Moria. This version is essentially unplayable (see invisible doesn't work, stores all close after 32768 turns, etc.) The following versions are not compatible with Umoria, and Umoria spoiler files may not apply to them. I don't know much about these versions. UB Moria 5.0: Also known as VMS Moria 5.0, this is the current version of VMS Moria. It has more monsters, a Black Market, and other features. Imoria 4.9: This is apparently a very good game, with new character classes and other features. It is now available for VMS and Linux only; it has not yet been ported to DOS or other Unix platforms. Amiga Moria 3.0: Although this version was originally based on 4.85, it has many added monsters, features, and bugs (including items which make you virtually invincible). BOSS: This game changes the setting of Moria, but keeps many of the items. It is based on VMS Moria 5.0. Pmoria: A version of Moria based on 5.5.0, with many enhancements. Morgul: An expanded version of Moria, keeping a similar setting. It is based on Umoria 5.5.0. Angband: Another expanded version of Moria with a similar setting. It is based on Umoria 5.2.1; current versions include some of the bug fixes from later versions. Although the basic game structure is similar to Moria's, there have been many enhancements. For more information, read the USENET group rec.games.roguelike.angband. Q7. I think I've found a bug; what should I do? When you are reporting a suspected bug, make sure to give the version number and the system. The bug report can be posted here or sent to me. If someone else maintains the game on your machine, the bug report should also be sent to him or her; the bug may be in a change on your machine but not in my code. If you have a patch for the bug, it would be best to send the patch by Email, so that I can check the patch before releasing it. If you report a bug which has been fixed in the current version, I may be able to send you a patch, or at least tell you that you can fix the bug by upgrading. If the bug hasn't been fixed, a good bug report may make it easy to fix. The following bugs have been reported with some frequency. Fixes are included where known; for 5.x versions, and 4.8x if you don't have a character you need to preserve, the best fix is to upgrade. All versions are Umoria unless indicated otherwise. All versions: Occasional rooms are created with no exit. The only attempt to fix this bug introduced others and had to be undone. 4.87-5.2.2: The game locks up if you wait in place for about 10,000 turns. This can be fixed in the source; in the function compact_monsters() in misc1.c, change "if (cur_dis > m_ptr.cdis)" to "if (cur_dis < m_ptr.cdis)". If you can't fix the bug, leave the level if you see lots of "Compacting monsters..." messages. 4.87-5.2.1: Your carrying capacity decreases. This cannot be fixed for an individual character without hacking the savefile, or modifying the program to fix the savefile. To avoid it, don't use spikes, and don't fight while wielding arrows in 4.87. 5.1.0-5.2.0: Invisible monsters which don't move or attack are sometimes created. Get off the level if you see one. 4.87: Monsters sometimes chase you in the wrong direction. 4.87: Wands/spells of polymorph and drain life work only when you are adjacent to the monster. 4.85: Several annoying bugs still exist, but this version is at least playable. 4.83: Many bugs. Upgrade. Druid: Potions of Healing can heal you above your maximum hit points. OS/2 Moria: Erick the Honest takes over all the stores eventually, and refuses to stock expensive items. This cannot be fixed by transferring a character from OS/2 to other versions. Amiga Moria 3.0: Some items make you extremely fast (and hungry). Amiga Moria 3.0: The system crashes when you leave the game, because it tries to close the screen without deactivating it. Jump to the workbench screen _instantly_ as the save (or exit) commences via [left amiga + N] and activate the workbench screen via a mouseclick or [alt + left amiga] (the keyboard shortcut for a mouse-click). Q8. What are the special abilities of ego weapons? Crowns? Amulet of the Magi? Cloak of Protection? All version-dependent changes are marked in brackets. Amulet of the Magi free action, see invisible, searching, +3 AC. [no searching bonus in 4.87] Cloak of Protection no special ability, just a larger bonus than usual. Ego weapons: (HA) Holy Avenger +(1-4) str, +(1-4) AC, (SE), (SU), sustain stat, see invisible. (DF) Defender stealth, regeneration, free action, see invisible, feather fall, RF, RC, RL, RA, +(6-10) to AC (SM) Slay Monster Damage (x 2) vs. monsters, see invisible. [found in 4.87 only] (SA) Slay Animal Damage (x 2) vs. animals, [does not exist in 4.87; has see invisible through 5.1.4] (SD) Slay Dragon Damage (x 4) vs. dragons. (SE) Slay Evil Damage (x 2) vs. evil monsters. (SU) Slay Undead Damage (x 3) vs. undead, [see invisible in 5.1.5 and later] (FT) Flame Tongue Damage (x 1.5) vs. monsters harmed by fire. (FB) Frost Brand Damage (x 1.5) vs. monsters harmed by cold. A HA which is +1 to strength sustains strength; +2, intelligence; +3, wisdom; +4, constitution (not dexterity). Crown of the Magi +(1-3) int, (RF), (RC), (RA), (RL) [In 4.87, it had see invisible instead of RL] Crown of Lordliness +(1-3) wis, chr. Crown of Might +(1-3) str, dex, con, free action. Crown of Seeing see invisible, +(10-25) searching. [+(2-5) to seach in 4.87] Crown of Regeneration Regeneration. Crown of Beauty +(1-3) charisma. Regeneration lets you recover mana and hit points at 1.5 times the normal rate, but also makes you use up food much more quickly. Free action prevents you from being slowed or paralyzed by monsters. Q9. How much damage do spells and wands do? Spell Name 4.87 damage 5.1.0 and later damage Magic Missile 2d6 2d6 Stinking Cloud 8 12 Lightning Bolt 3d8 4d8 Lightning Ball 24 32 Frost Bolt 4d8 6d8 Frost/Cold Ball 32 48 Acid Ball 40 60 Fire Bolt 6d8 9d8 Fire Ball 48 72 Wand of Drain Life 50 75 [in 5.1.4 and later] In 5.x only, a wand of wall building will do 4d8 damage to any creature buried in the wall (except one that moves through walls), and will kill any immobile creature. On the creature's next turn, it will attempt to move out of the wall, and if it is unable to do so, it will take 10d8 damage and dig its way out. Everything below is the same in all versions. Wand of Light/Staff of 2d8 (if sensitive) Starlight Stone to Mud 100 (if sensitive) Orb of Draining 3d6 + caster's level, double to evil creatures Dispel Undead/Evil 1-60 from scroll or staff; 1 up to triple caster's level from spell Holy Word Dispel evil for 1 up to quadruple caster's level Notes: All mage spells in 4.87 do the damage listed in the table above if cast from a wand, and 1 point more if cast by a mage. All ball spells do full damage for a direct hit, half damage one space away, and 1/3 damage two spaces away. Q10. What does spell Y do? Non-obvious spell effects: Mage spells: Phase Door: short-range teleport. Find Hidden Traps/Doors: also detects stairs. Sleep I: sleep one monster in a given direction. Recharge Item I: fewer charges than Recharge Item II, and more likely to fail. Sleep II: sleep all monsters adjacent to player. Sleep III: sleep all monsters with a line of sight to player (including invisible ones). Word of Destruction: obliterates everything within 15 spaces of the player; Balrog will teleport to another level. Priest spells: Bless: +2 to AC, and +5 to chance to hit (equivalent to +1-2/3 bonus on weapon) for a short time. Blind Creature: blinded creatures wander around confused until they recover. Portal: medium-range teleport. Chant: double duration Bless. Sanctuary: sleep creatures adjacent to player. Protection from Evil: prevents any evil creature of the player's level or lower from attacking the player. Earthquake: causes random walls and ceilings in the area to collapse, possibly injuring anything nearby. Turn Undead: all undead of the player's level or lower, and some of higher level, will attempt to flee [in 5.5.0 and earlier versions, they will be confused] Prayer: quadruple duration Bless. Dispel Undead/Evil: affects all undead/evil within line of sight (even invisble ones in 5.x versions), damage is from 1 up to 3x player's level, 1-60 from scroll or staff. Glyph of Warding: creates a glyph which monsters cannot enter, but have a small chance of breaking. Holy Word: heals player completely, cures poison and fear, and dispels evil for 1 to 4x player's level. [In 5.5.1 and later versions, also restores all stats, and makes player invulnerable for 3 turns.] Q11. On what level do you find X? Where important objects are found: In 4.87, 1/20 of items are chosen as if you were on level 50. In 5.1 and all later versions, 1/12 of items are chosen as if you were on a deeper level, which has (current level/50) chance of being level 50; this check is not made in town. This affects only the type of item, not its enchantment. Items become somewhat less common as you go deeper than the indicated levels; however, if you can survive down there, this is compensated for by the fact that there are more treasures on deeper levels. Item type Level Ego weapons, special armor, Progressively more common as you get boots, gloves, helmets deeper, all the way to level 55 Healing potion 12 Gain stat potions 25 Restore mana potion 25 Invulnerability potion 40 Gain experience potion 50 Genocide scroll 35 Destruction scroll 40 Rune of Protection scroll 50 Mass Genocide scroll 50 Amulets of wisdom, charisma 20 Gain str/int/dex/con rings 30 Amulet of the magi 50 Ring of speed 50 Staff of speed 40 Staff of mass polymorph 46 Staff of dispel evil 49 Staff of destruction 50 Wand of clone monster 15 [2 in 4.87] Wand of drain life 50 Q12. How many attacks can I get with this weapon? Here is the table (for 5.x) for the number of blows for a given strength and dexterity. If your strength or dexterity is 18+xx, that is stored as 18/xx; thus, for example, you need an 18/90 strength to use the bottom row of the table with a katana (12 pounds). If you don't know the weight of a weapon, set the option "Show weights in inventory." /* used to calculate the number of blows the player gets in combat */ int8u blows_table[7][6] = { /* STR/W: 9 18 67 107 117 118 : DEX */ /* <2 */ { 1, 1, 1, 1, 1, 1 }, /* <3 */ { 1, 1, 1, 1, 2, 2 }, /* <4 */ { 1, 1, 1, 2, 2, 3 }, /* <5 */ { 1, 1, 2, 2, 3, 3 }, /* <7 */ { 1, 2, 2, 3, 3, 4 }, /* <9 */ { 1, 2, 2, 3, 4, 4 }, /* >9 */ { 2, 2, 3, 3, 4, 4 } }; Q13. How do you kill an ancient multi-hued dragon? Usually, you don't want to try; one gas breath from a full-strength AMHD does 693 damage, with no resistance. If you can get to speed 3 (one permanent speed item, and either another permanent speed item or a haste self spell or staff), you can try this technique. First, create (or find in a maze room) a wall with one open space on all four sides. . .#. . Stand on one side, with the dragon on the other side. When the dragon moves adjacent to you, attack it once, and then hide behind the pillar. The dragon can't see you, so it won't breathe, and will instead chase you to another side. Now attack once, and hide again, and so on until the dragon is finished. Q14. How do you kill an emperor lich? You can kill an emperor lich if you can get to speed 2, which is its speed. A mage or ranger can do this with the spell of haste self; anyone else needs a staff of speed, potion of haste self, or permanent speed item. You will also need about 10 cure critical wounds or cure serious wounds potions, and some item giving you free action. You also need some ranged spell attack. Liches take double damage from lightning in 5.x versions, so the spell of lightning bolt or wand of lightning balls is a good choice. Rogues and warriors will need several wands, with a total of about 30 charges to guarantee that they can kill the lich with them. A priest or paladin has Orb of Draining, which is even better. Now, try to line up with the lich while you are not adjacent to it, either in a room or a corridor. This gives you a chance to cast your spell. The lich will get one action. If it cast a spell and you resisted, or the spell didn't do anything harmful, you have another chance. If you were confused or blinded, drink a cure wounds potion; the lich isn't adjacent to you, so it can't hurt you. If the lich moved and is now adjacent to you, move back. Try to avoid getting cornered, and phase door or portal away if you are. A priest can make this easier by putting down a glyph of warding, but this must be done *before* the lich chases you across the glyph. (Don't stand on the glyph; it isn't foolproof.) If you run low on mana and don't have a wand, teleport out and come back later to finish the job. A priest with glyph of warding can also set up the following configuration (the exact length doesn't matter as long as you are within spell range): #L##### #^^...@ ####### The lich cannot cast spells from this position, because it cannot see you. As long as it doesn't break the glyphs, you are safe, and can fire Orb of Draining down the corridor; the lich will take some damage each time. If the lich breaks either glyph, run or teleport out, and continue the battle elsewhere. I do not advise trying this technique against an AMHD; it will probably break a glyph before the battle is over, and if your teleport spell fails, or if you haven't hasted yourself, the AMHD gets a chance to breathe. An emperor lich has 1520 hit points, plus anything additional that it gains by draining mana (6 points per mana point drained) and charges (40 points per charge). Never let it attack you in melee, because it can destroy your wands, healing itself in the process, as well as draining your experience and dexterity. If you can get to speed 3, faster than the lich, it is easy to kill; just fight, move back, fight, move back, and so on. You will still need a lot of cure wounds potions, unless you let it chase you around a pillar, as in the AMHD technique. Q15. What is the grape jelly trick? Does it work in Umoria 5.x? The Grape Jelly trick is a spoiler/workaround/trick which is no longer necessary in 5.1 and later versions. In 4.87, when your intelligence and constitution changed, your mana and hit points did not change. Thus, in order to get the benefit of the increased values, you have to let a grape jelly (or other creature, but grape jellies are otherwise harmless) drain you to a low level, and then drink restore life levels potions to go back up with the increased stats. Q16. I don't like haggling; can I change the source code to turn it off? If you have the source code for any 5.x version, you can turn off haggling with a simple change. Here is the change you would need to make. (Note: This is *not* an official patch.) In the source file store1.c, this is the routine for determining whether you need to haggle. You can change the function, or simply change the return(flagnoneed) to return(TRUE) to eliminate all haggling. The code here is from versions 5.5.1 and 5.5.2; the text of the function is slightly different in earlier versions. int noneedtobargain(store_num, minprice) int store_num; int32 minprice; { register int flagnoneed; int bargain_record; register store_type *s_ptr; s_ptr = &store[store_num]; if (s_ptr->good_buy == MAX_SHORT) return TRUE; bargain_record = (s_ptr->good_buy - 3 * s_ptr->bad_buy - 5); flagnoneed = ((bargain_record > 0) && ((long)bargain_record * (long)bargain_record > minprice/50)); return (flagnoneed); } Q17. How do you create objects in wizard mode? You will need the source; if you have only executables, get the source files constant.h and treasure.c from the archive, which contain the necessary definitions. This is an explanation of some of the parameters. Tval: This is defined in constant.h; it is the value for the item type. For example, TV_WAND is 65. Tchar: The character used to represent this object; it should usually be proper for the item type. Subval: This identifies the specific item. If you are duplicating an item from the item list, use the same subval (and tval) as that item; otherwise, don't. Use subvals 0-63 for items that shouldn't stack, 64-127 for items that should always stack (potions and scrolls), 193 or more for items that are generated in a group, and should stack as that group (arrows). Weight: In tenths of a pound. P1: Used for all special bonuses which don't appear elsewhere: bonus to stats/searching/stealth/speed, which stat to sustain (warning: constitution is 4 and dexterity 5), tunneling value, food value, light value of a lamp, torch, or flask of oil. For missiles, different values of P1 distinguish different groups of missiles; use small negative numbers if you create groups as a wizard. For bows, slings, and crossbows, the values identify the weapon type; use the same value that is used for the corresponding weapon in treasure.c. Flags: A hexadecimal number which contains: for wearable items, all special effects (bits beginning with TR_ in constant.h). for chests, trap flags (CH_ bits in constant.h) and treasure flags (CM_ bits in constant.h). The CM_WIN flag is cleared when you open a chest, so you can't create a chest with that bit set in order to get an instant win. for potions/scrolls/staffs/wands, the effects of using the item (see the items in treasure.c). Many potions have multiple effects (cure light wounds also cures blindness). for books, which spells are in the book (spell 1 is the units bit). Level: Level on which the item would be found. This affects the difficulty of using wands and staffs. The object will have no name, except for the inscription {wizard item}, and possibly a type name, such as "Potion of"; you can change the inscription. -- David Grabiner, grabiner@alumni.princeton.edu http://math.la.asu.edu/~grabiner Shop at the Mobius Strip Mall: Always on the same side of the street! Torus Coffee and Donuts, Klein Glassworks, Projective Airlines, etc. moria-5.6.debian.1/build/copyright0000644000175000017500000000242611074750560015226 0ustar pjbpjbThis package was debianized by Rene Weber rene_debmaint@elvenlord.com on Sun, 28 May 2000 16:35:38 -0400. It was downloaded from ftp://ftp.greyhelm.com/pub/Games/Moria/source/ Changes to make the original source conformant with the Debian Policy Manual were minor (directory structure, mostly) and are documented in the changelog file. The upgrade to version 5.6 has not yet been debianized. Upstream Author(s): David Grabiner Copyright: (from source files version 5.6) Copyright (C) 1989-2008 James E. Wilson, Robert A. Koeneke, David J. Grabiner This file is part of Umoria. Umoria is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Umoria is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Umoria. If not, see . */ October 13, 2008 moria-5.6.debian.1/build/preinst0000644000175000017500000000131510757653306014705 0ustar pjbpjb#!/bin/sh -e # Shamelessly stolen from Joey Hess' bsdgames-2.12-9 SCOREFILES=" /var/games/moria/scores" # We used to keep score files in /var/lib/games, and if files are there, # move them into the new location. if [ -d /var/lib/games ]; then # Have to set up directory hierarchy, since this is running as a # preinst. mkdir -p /var/games/moria chown root.games /var/games/moria chmod g+rws /var/games/moria for file in $SCOREFILES; do oldfile=`echo $file | sed s:/var/games/:/var/lib/games/:` if [ -e $oldfile ]; then if [ ! -e $file ]; then mv -f $oldfile $file else rm -f $oldfile fi fi done # Delete the old directory hierarchy. rm -rf /var/lib/games/moria fi #DEBHELPER# moria-5.6.debian.1/build/docs0000644000175000017500000000023010757653306014144 0ustar pjbpjbREADME changelog doc/moria1.txt doc/moria2.txt doc/pronounc doc/spells.doc doc/FEATURES.NEW doc/dragon.inf doc/exp.doc doc/history doc/faq doc/faq.2001 moria-5.6.debian.1/build/menu0000644000175000017500000000013710757653306014166 0ustar pjbpjb?package(moria):needs=text section=Games/Adventure\ title="Moria" command="/usr/games/moria" moria-5.6.debian.1/build/dirs0000644000175000017500000000006210757653306014160 0ustar pjbpjbvar/games/moria usr/lib/games/moria etc usr/games moria-5.6.debian.1/build/control0000644000175000017500000000215610757653306014705 0ustar pjbpjbSource: moria Section: non-free/games Priority: optional Maintainer: Rene Weber Build-Depends: debhelper (>= 2.0.86), libncurses-dev Standards-Version: 3.5.6.0 Package: moria Architecture: any Depends: ${shlibs:Depends} Conflicts: suidmanager (<< 0.50) Description: A roguelike game with an infinite dungeon NOTE: despite the package name, this is actually UMORIA 5.5.2. . A single player roguelike game with a regenerating dungeon, moria is the predecessor of angband with a full-screen, text-based, turn-based interface. It features scrolling maps, and an infinite (constantly regenerated) dungeon. . Moria's dungeons are populated by monsters, some of which are inspired by J.R.R. Tolkien's books. The goal of the game is to find and kill the Balrog, whereupon the player is crowned King. Your player can be created from a combination of 8 races (human, half-elf, elf, halfling, gnome, dwarf, half-orc, half-troll) and 6 classes (warrior, mage, priest, rogue, ranger, paladin), and is measured by 6 attributes (strength, dexterity, intelligence, wisdom, constitution, and charisma). moria-5.6.debian.1/ChangeLog0000644000175000017500000000741111074756452013753 0ustar pjbpjb2008-10-13 David Grabiner * All: Update all copyright/license notices to GPL; Files in atari_st/curscomp and mac/scrnmgr still refer to old licenses as they are stand-alone programs. 2008-09-01 David Grabiner * config.h: Add new LICENSE file for GPL. * dungeon.c (do_command,original_commands), origcmds.hlp, roglgmds.hlp: New command ^V to view the GPL. * files/news: Added reference to GPL. 2008-06-01 David Grabiner * config.h, externs.h, *.c: Include stdio.h and stdlib.h unconditionally rather than guarding them and sometimes dealing with incorrect prototypes * io.c: Include unistd.h for execl() on Unix and linux systems. 2008-05-26 David Grabiner * config.h: Gave up on ## because it is so ugly in ANSI C. 2008-02-22 David Grabiner * types.h: use stdint.h to get guaranteed 16-bit and 32-bit types rather than relying on the length of a long, which varies by compiler. * config.h: use ## operator so that MORIA_LIB works correctly. * INSTALL: Note that default install is for Debian, so UNIX install needs to copy the Makefile. moria (5.5.2-5) unstable; urgency=low * Changed location of score file from /var/lib/games/moria/scores to /var/games/moria/scores per FHS. (Closes: #115849) * Fixed handling of score file on upgrades (do not null it out!). * Applied fixes to a few buffer overflows. (Thanks to Lars Helgeland for noticing the overflows and supplying the patches.) (Closes: #115745) * Upgraded policy to version 3.5.6.0. -- Rene Weber Wed, 24 Oct 2001 22:44:05 -0400 moria (5.5.2-4) unstable; urgency=low * Fixed dependencies (was compiled against libncurses4, what was I doing that day?). * Corrected explanation of the 'V' command in moria2.txt (but not in the nroff source for that documentation). * Removed use of dh_suidregister. -- Rene Weber Mon, 9 Jul 2001 23:31:01 -0400 moria (5.5.2-3) unstable; urgency=low * Added a Build-Depends line. * Changed the handling of the build directory for the convenience of porters (should have no impact on users). * Changed short description so that it does not include the name of the package. * Corrected path to /usr/games/moria binary in the menu. Closes: #81353 -- Rene Weber Sat, 6 Jan 2001 02:47:02 -0700 moria (5.5.2-2) unstable; urgency=low * Fixed typos in the control/README.debian file * Updated the author's e-mail address in the copyright file * Updated the author's web page listed in the README.debian * Installed a new version of the FAQ (reflecting the author's move) -- Rene Weber Sat, 14 Oct 2000 10:23:48 -0700 moria (5.5.2-1) unstable; urgency=low * Initial Release. * Added DEBIAN_LINUX #define to handle code customizations. * Needed to include termios.h in io.c * All instances of signal() changed to sysv_signal() since libc6 defaults to BSD semantics. * Instead of redefining getuid, just ifdeffed it out of unix.c * Changed LOCK_EX and LOCK_SH definitions in death.c (to avoid redefinition warnings). * Library files are in /usr/lib/games/moria except for the scores file which is in /var/lib/games/moria and the hours file which has been renamed to /etc/moria-hours * Makefile changed to make the binary setgid instead of setuid, as required by Debian Policy 5.10. None of the code itself needed to be touched, since it already relinquished uid and gid in the original code. * Saved game file is named ".moria-save" not "moria-save" -- Rene Weber Sun, 28 May 2000 16:35:38 -0400